题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=2243

题意:中文题目

思路:树链剖分。首先考虑求区间颜色段数的问题, 我们可以用线段树维护:区间左右端点(st,ed),区间颜色段数(val),懒惰标记(lazy:是否整个区间被染成同一种颜色),区间左右端点的颜色(lcolor,rcolor),然后在查询的时候如果当前区间的左子树的右端点的颜色等于右子树的左端点的颜色,那么查询答案要减一。由于树链剖分在查询时是有可能两端的分链一起向上爬的。所以我们在查询时需要记录两端上一次查询结果的deep小的那个点的颜色。如果当前查询的链和上一次查询的交接处位置颜色一致那么答案就要减一。

注意: 颜色可能为0

#define _CRT_SECURE_NO_DEPRECATE
#include<iostream>
#include<cstring>
#include<string>
#include<algorithm>
#include<stdio.h>
#include<queue>
#include<vector>
#include<stack>
#include<map>
#include<set>
#include<time.h>
#include<cmath>
#include<sstream>
#include<assert.h>
using namespace std;
#define L(x) x<<1
#define R(x) x<<1|1
typedef long long int LL;
const int inf = 0x3f3f3f3f;
const LL INF = 0x3f3f3f3f3f3f3f3fLL;
const int MAXN = 1e5 + 10;
int head[MAXN], tot, cnt,value[MAXN];
struct Edge{int to, next;
}Edges[MAXN * 2];
void add(int u, int v){Edges[tot].to = v;Edges[tot].next = head[u];head[u] = tot++;
}
int id[MAXN], son[MAXN], deep[MAXN], size[MAXN], fa[MAXN], reid[MAXN], top[MAXN];
void Init(){tot = 0; cnt = 0;memset(head, -1, sizeof(head));memset(son, -1, sizeof(son));
}
void DFS1(int u, int p,int dep){fa[u] = p; size[u] = 1; deep[u] = dep;for (int i = head[u]; i != -1; i = Edges[i].next){if (Edges[i].to != p){DFS1(Edges[i].to, u,dep+1);size[u] += size[Edges[i].to];if (son[u] == -1 || size[Edges[i].to] > size[son[u]]){son[u] = Edges[i].to;}}}
}
void DFS2(int u, int tp){id[u] = ++cnt; reid[id[u]] = u; top[u] = tp;if (son[u] == -1){ return; }DFS2(son[u], tp);for (int i = head[u]; i != -1; i = Edges[i].next){if (son[u] != Edges[i].to&&Edges[i].to != fa[u]){DFS2(Edges[i].to, Edges[i].to);}}
}
struct Node{int st, ed;int lazy,val, lcolor,rcolor;//懒惰标记,颜色段数,区间左右端点的颜色
}Seg[MAXN * 4];
void pushUp(int k){Seg[k].lcolor = Seg[L(k)].lcolor;Seg[k].rcolor = Seg[R(k)].rcolor; Seg[k].val = Seg[L(k)].val + Seg[R(k)].val;if (Seg[L(k)].rcolor == Seg[R(k)].lcolor){Seg[k].val--;}
}
void pushDown(int k){//颜色可能等于0if (Seg[k].lazy!=-1){Seg[L(k)].val = 1;Seg[L(k)].lcolor = Seg[L(k)].rcolor = Seg[L(k)].lazy = Seg[k].lazy;Seg[R(k)].val = 1;Seg[R(k)].lcolor = Seg[R(k)].rcolor = Seg[R(k)].lazy = Seg[k].lazy;Seg[k].lazy = -1;}
}
void Build(int l, int r, int k){Seg[k].st = l; Seg[k].ed = r;  Seg[k].lazy = -1;if (l == r){Seg[k].val = 1;Seg[k].lcolor = Seg[k].rcolor = value[reid[l]];return;}int mid = (l + r) / 2;Build(l, mid, L(k)); Build(mid + 1, r, R(k));pushUp(k);
}
void Modify(int l,int r,int val,int k){ if (Seg[k].st == l&&Seg[k].ed == r){Seg[k].lazy = Seg[k].lcolor = Seg[k].rcolor = val;Seg[k].val = 1;return;}pushDown(k);if (r <= Seg[L(k)].ed){Modify(l, r, val, L(k));}else if (l >= Seg[R(k)].st){Modify(l, r, val, R(k));}else{Modify(l, Seg[L(k)].ed, val, L(k));Modify(Seg[R(k)].st, r, val, R(k));}pushUp(k);
}
void Modify(int u, int v,int val){int f1 = top[u], f2 = top[v];while (f1 != f2){if (deep[f1] < deep[f2]){swap(f1, f2);swap(u, v);}Modify(id[f1], id[u], val,1);u = fa[f1]; f1 = top[u];}if (deep[u] > deep[v]){swap(u, v);}Modify(id[u], id[v],val, 1);
}
Node Query(int l, int r, int k){
//求区间有多少段颜色。并且保存这段区间左端点和右端点的颜色if (Seg[k].st == l&&Seg[k].ed == r){return Seg[k];}Node ans;pushDown(k);if (r <= Seg[L(k)].ed){ans = Query(l, r, L(k));}else if (l >= Seg[R(k)].st){ans = Query(l, r, R(k));}else{Node ansL= Query(l, Seg[L(k)].ed, L(k)),ansR=Query(Seg[R(k)].st,r,R(k));ans.val = ansL.val + ansR.val;ans.lcolor = ansL.lcolor; ans.rcolor = ansR.rcolor;if (ansL.rcolor == ansR.lcolor){ans.val--;}}pushUp(k);return ans;
}
int Query(int u, int v){int ans = 0,Lrc=-1,Rlc=-1;//保存上次询问时两端区间查询时deep比较小的点的颜色,因为可能两端同时上升爬int f1 = top[u], f2 = top[v];while (f1 != f2){if (deep[f1] < deep[f2]){swap(f1, f2);swap(u, v);swap(Lrc, Rlc);}Node temp = Query(id[f1], id[u], 1);ans += temp.val - (Lrc == temp.rcolor);u = fa[f1]; f1 = top[u]; Lrc = temp.lcolor;}if (deep[u] > deep[v]){swap(u, v);swap(Lrc, Rlc);}Node temp = Query(id[u], id[v], 1);ans += temp.val - (temp.rcolor == Rlc) - (temp.lcolor == Lrc);return ans;
}
int main(){
//#ifdef kirito
//    freopen("in.txt", "r", stdin);
//    freopen("out.txt", "w", stdout);
//#endif
//    int start = clock();int n,m;while (~scanf("%d%d",&n,&m)){Init();for (int i = 1; i <= n; i++){scanf("%d", &value[i]);}for (int i = 1; i < n; i++){int u, v;scanf("%d%d", &u, &v);add(u, v); add(v, u);}DFS1(1, 1, 0);  DFS2(1, 1); Build(1, n, 1);while (m--){char ope[10];int u, v, w;scanf("%s", ope);switch (ope[0]){case 'C': scanf("%d%d%d", &u, &v, &w); Modify(u, v, w); break;default: scanf("%d%d", &u, &v); printf("%d\n", Query(u, v)); break;}}}
//#ifdef LOCAL_TIME
//    cout << "[Finished in " << clock() - start << " ms]" << endl;
//#endifreturn 0;
}

转载于:https://www.cnblogs.com/kirito520/p/6500817.html

BZOJ 2243 树链剖分相关推荐

  1. BZOJ 4811 树链剖分+线段树

    思路: 感觉这题也可神了.. (还是我太弱) 首先发现每一位不会互相影响,可以把每一位分开考虑,然后用树链剖分或者LCT维护这个树 修改直接修改,询问的时候算出来每一位填0,1经过这条链的变换之后得到 ...

  2. bzoj 4196 树链剖分 模板

    [Noi2015]软件包管理器 Time Limit: 10 Sec  Memory Limit: 512 MB Submit: 2135  Solved: 1232 [Submit][Status] ...

  3. BZOJ 2836 树链剖分+线段树

    思路: 链剖+线段树裸题 重链的标号就是DFS序 所以查子树的时候每回就 query(change[x],change[x]+size[x]-1) 就好了 剩下的应该都会吧.. //By Sirius ...

  4. 关于轻重边及树链剖分该怎么写...

    AC BZOJ 1787 轻重边剖分LCA 1 #include <cstdio> 2 #include <fstream> 3 #include <iostream&g ...

  5. BZOJ 2243 染色(树链剖分好题)

    2243: [SDOI2011]染色 Time Limit: 20 Sec  Memory Limit: 512 MB Submit: 7971  Solved: 2990 [Submit][Stat ...

  6. BZOJ 2157 「国家集训队」旅游(树链剖分,线段树,边权转点权)【BZOJ计划】

    整理的算法模板合集: ACM模板 点我看算法全家桶系列!!! 实际上是一个全新的精炼模板整合计划 题目链接 https://hydro.ac/d/bzoj/p/2157 是 hydro 的 BZOJ ...

  7. BZOJ 2402 陶陶的难题II (树链剖分、线段树、凸包、分数规划)

    毒瘤,毒瘤,毒瘤-- \(30000\)这个数据范围,看上去就是要搞事的啊... 题目链接: https://www.lydsy.com/JudgeOnline/problem.php?id=2402 ...

  8. HDU 3966 POJ 3237 HYSBZ 2243 HRBUST 2064 树链剖分

    树链剖分是一个很固定的套路 一般用来解决树上两点之间的路径更改与查询 思想是将一棵树分成不想交的几条链 并且由于dfs的顺序性 给每条链上的点或边标的号必定是连着的 那么每两个点之间的路径都可以拆成几 ...

  9. 树链剖分——线段树区间合并bzoj染色

    线段树区间合并就挺麻烦了,再套个树链就更加鬼畜,不过除了代码量大就没什么其他的了.. 一些细节:线段树每个结点用结构体保存,pushup等合并函数改成返回一个结构体,这样好写一些 struct Seg ...

最新文章

  1. 最简单的CI框架入门示例--数据库取数据
  2. Nginx 做图片服务器
  3. 为什么程序员都不写文档?
  4. ps随机排列_漂亮!自然材料:人工可控微米级胶体粒子“堆积木”——粒子随心所欲的组装排列!...
  5. [蓝桥小记]蓝桥杯参赛经历分享
  6. 上传 录音_老罗推荐的是最好吗?AI旗舰录音笔对比评测
  7. oracle 测试库搭建,Oracle Study之--通过RMAN克隆测试库
  8. 数据库笔记10:创建与管理视图
  9. 斜面孔如何绘制_如何才能做好钢结构厂房基础设计
  10. php开发_图片验证码
  11. docker_5 DockerFile
  12. 第 4 周 关于 startActivityForResult
  13. Atitit 概念还是技术更重要
  14. Java8下载安装详细教程,环境配置,Java、jre下载安装教程,此电脑图标位置,电脑处理器版本查询查询
  15. 我本将心向明月,奈何明月照沟渠
  16. 有自学能力的人,赚钱极其简单—明风社
  17. Qt模仿QQ聊天窗口界面(一)
  18. Shader的合并同类项
  19. 如何解决百度网盘下载速度慢的问题
  20. 谈谈 996 背后的现象

热门文章

  1. HTTP POST发消息
  2. 巧用推荐墙入口,APP轻松盈利
  3. CAS的ABA问题及解决方案
  4. 接口测试---mock变量自定义变量的使用
  5. 程序员一人对接四人郁闷吐槽:轮流指挥,只有我从天亮忙到天黑
  6. 小白转前端,学习哪些知识点才能不走弯路?
  7. 计算机 学校教一半 自学一半,一半初中生无缘普高,上职业学校怎么样?
  8. 计算机专业基础融合,【计算机专业论文】计算机专业产教融合转型发展模式探析(共2546字)...
  9. php主页显示商品预览图代码,在ECSHOP留言板页面显示商品缩略图方法
  10. 视频点播服务器实现视频转码和视频播出功能