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

树链剖分的点剖分+线段树。漏了一个小地方,调了一下午...... 还是要细心啊!

结构体里lc表示这个区间的最左端的颜色,rc表示这个区间的最右端的颜色,sum表示这个区间的颜色段数目。回溯合并的时候要注意,左孩子的右端颜色要是等于右孩子左端颜色 sum就要-1。

代码如下:

 #include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
const int MAXN = 2e5 + ;
struct data {
int next , to;
}edge[MAXN << ];
struct segtree {
int l , r , sum , lazy; //sum表示颜色段数量,lazy表示颜色延迟标记
int lc , rc; //lc表示区间的最左端颜色,rc表示最右端颜色
}T[MAXN << ];
int head[MAXN] , tot;
int son[MAXN] , size[MAXN] , par[MAXN] , dep[MAXN] , cnt;
int top[MAXN] , id[MAXN] , fid[MAXN];
int a[MAXN]; void init() {
memset(head , - , sizeof(head));
tot = cnt = ;
} inline void add(int u , int v) {
edge[tot].next = head[u];
edge[tot].to = v;
head[u] = tot++;
} void dfs1(int u , int p , int d) {
dep[u] = d , size[u] = , son[u] = u , par[u] = p;
for(int i = head[u] ; ~i ; i = edge[i].next) {
int v = edge[i].to;
if(v == p)
continue;
dfs1(v , u , d + );
if(size[v] >= size[son[u]])
son[u] = v;
size[u] += size[v];
}
} void dfs2(int u , int p , int t) {
top[u] = t , id[u] = ++cnt;
fid[cnt] = u;
if(son[u] != u)
dfs2(son[u] , u , t);
for(int i = head[u] ; ~i ; i = edge[i].next) {
int v = edge[i].to;
if(v == p || v == son[u])
continue;
dfs2(v , u , v);
}
} void pushdown(int p) {
if(T[p].lazy != -) {
int ls = p << , rs = (p << )|;
T[ls].rc = T[ls].lc = T[rs].lc = T[rs].rc = T[p].lazy;
T[ls].lazy = T[rs].lazy = T[p].lazy;
T[ls].sum = T[rs].sum = ; //变成同一个颜色 sum就为1了
T[p].lazy = -;
}
} void pushup(int p) {
T[p].lc = T[p << ].lc , T[p].rc = T[(p << )|].rc; //这里注意要回溯上来,父节点的左右端颜色要更新
T[p].sum = T[p << ].sum + T[(p << )|].sum - (T[p << ].rc == T[(p << )|].lc); //合并操作:要是左孩子的最右端颜色等于右孩子最左端颜色,那就需要-1
} void build(int p , int l , int r) {
int mid = (l + r) >> ;
T[p].r = r , T[p].l = l , T[p].lc = a[fid[l]] , T[p].rc = a[fid[r]] , T[p].lazy = -;
if(l == r) {
T[p].sum = ;
return ;
}
build(p << , l , mid);
build((p << )| , mid + , r);
pushup(p);
} void update(int p , int l , int r , int color) {
int mid = (T[p].l + T[p].r) >> ;
if(T[p].l == l && T[p].r == r) {
T[p].sum = , T[p].lazy = T[p].rc = T[p].lc = color;
return ;
}
pushdown(p);
if(r <= mid) {
update(p << , l , r , color);
}
else if(l > mid) {
update((p << )| , l , r , color);
}
else {
update(p << , l , mid , color);
update((p << )| , mid + , r , color);
}
pushup(p);
} int query(int p , int l , int r) {
int mid = (T[p].l + T[p].r) >> ;
if(T[p].l == l && T[p].r == r) {
return T[p].sum;
}
pushdown(p);
if(r <= mid) {
return query(p << , l , r);
}
else if(l > mid) {
return query((p << )| , l , r);
}
else {
return query(p << , l , mid) + query((p << )| , mid + , r) - (T[p << ].rc == T[(p << )|].lc);
}
} int query_pos_color(int p , int pos) {
int mid = (T[p].l + T[p].r) >> ;
if(T[p].l == T[p].r && pos == T[p].r) {
return T[p].lc;
}
pushdown(p);
if(pos <= mid) {
query_pos_color(p << , pos);
}
else {
query_pos_color((p << )| , pos);
}
} void find_update(int u , int v , int val) {
int fu = top[u] , fv = top[v];
while(fu != fv) {
if(dep[fu] >= dep[fv]) {
update( , id[fu] , id[u] , val);
u = par[fu];
fu = top[u];
}
else {
update( , id[fv] , id[v] , val);
v = par[fv];
fv = top[v];
}
}
if(dep[u] > dep[v])
update( , id[v] , id[u] , val);
else
update( , id[u] , id[v] , val);
} int find_ans(int u , int v) {
int fu = top[u] , fv = top[v] , res = ;
while(fu != fv) {
if(dep[fu] >= dep[fv]) {
res += query( , id[fu] , id[u]);
if(query_pos_color( , id[fu]) == query_pos_color( , id[par[fu]])) //要是fu节点和其父节点颜色相同就-1
res--;
u = par[fu];
fu = top[u];
}
else {
res += query( , id[fv] , id[v]);
if(query_pos_color( , id[fv]) == query_pos_color( , id[par[fv]])) //上同
res--;
v = par[fv];
fv = top[v];
}
}
if(dep[u] > dep[v]) {
res += query( , id[v] , id[u]);
return res;
}
else {
res += query( , id[u] , id[v]);
return res;
}
} int main()
{
int n , m , u , v , val;
char q[];
while(~scanf("%d %d" , &n , &m)) {
init();
for(int i = ; i <= n ; ++i)
scanf("%d" , a + i);
for(int i = ; i < n ; ++i) {
scanf("%d %d" , &u , &v);
add(u , v);
add(v , u);
}
dfs1( , , );
dfs2( , , );
build( , , cnt);
while(m--) {
scanf("%s" , q);
if(q[] == 'Q') {
scanf("%d %d" , &u , &v);
printf("%d\n" , find_ans(u , v));
}
else {
scanf("%d %d %d" , &u , &v , &val);
find_update(u , v , val);
}
}
}
return ;
}

BZOJ 2243: [SDOI2011]染色 (树链剖分+线段树合并)的更多相关文章

  1. 2243: [SDOI2011]染色 树链剖分+线段树染色

    给定一棵有n个节点的无根树和m个操作,操作有2类: 1.将节点a到节点b路径上所有点都染成颜色c: 2.询问节点a到节点b路径上的颜色段数量(连续相同颜色被认为是同一段), 如“112221”由3段组 ...

  2. bzoj2243[SDOI2011]染色 树链剖分+线段树

    2243: [SDOI2011]染色 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 9012  Solved: 3375[Submit][Status ...

  3. 【BZOJ2243】[SDOI2011]染色 树链剖分+线段树

    [BZOJ2243][SDOI2011]染色 Description 给定一棵有n个节点的无根树和m个操作,操作有2类: 1.将节点a到节点b路径上所有点都染成颜色c: 2.询问节点a到节点b路径上的 ...

  4. B20J_2243_[SDOI2011]染色_树链剖分+线段树

    B20J_2243_[SDOI2011]染色_树链剖分+线段树 一下午净调这题了,争取晚上多做几道. 题意: 给定一棵有n个节点的无根树和m个操作,操作有2类: 1.将节点a到节点b路径上所有点都染成 ...

  5. BZOJ2243 [SDOI2011]染色(树链剖分+线段树合并)

    题目链接 BZOJ2243 树链剖分 $+$ 线段树 线段树每个节点维护$lc$, $rc$, $s$ $lc$代表该区间的最左端的颜色,$rc$代表该区间的最右端的颜色 $s$代表该区间的所有连续颜 ...

  6. BZOJ.4034 [HAOI2015]树上操作 ( 点权树链剖分 线段树 )

    BZOJ.4034 [HAOI2015]树上操作 ( 点权树链剖分 线段树 ) 题意分析 有一棵点数为 N 的树,以点 1 为根,且树点有边权.然后有 M 个 操作,分为三种: 操作 1 :把某个节点 ...

  7. BZOJ.1036 [ZJOI2008]树的统计Count ( 点权树链剖分 线段树维护和与最值)

    BZOJ.1036 [ZJOI2008]树的统计Count (树链剖分 线段树维护和与最值) 题意分析 (题目图片来自于 这里) 第一道树链剖分的题目,谈一下自己的理解. 树链剖分能解决的问题是,题目 ...

  8. BZOJ 3672[NOI2014]购票(树链剖分+线段树维护凸包+斜率优化) + BZOJ 2402 陶陶的难题II (树链剖分+线段树维护凸包+分数规划+斜率优化)

    前言 刚开始看着两道题感觉头皮发麻,后来看看题解,发现挺好理解,只是代码有点长. BZOJ 3672[NOI2014]购票 中文题面,题意略: BZOJ 3672[NOI2014]购票 设f(i)f( ...

  9. bzoj 4196 [Noi2015]软件包管理器 (树链剖分+线段树)

    4196: [Noi2015]软件包管理器 Time Limit: 10 Sec  Memory Limit: 512 MBSubmit: 2852  Solved: 1668[Submit][Sta ...

  10. bzoj 2157: 旅游【树链剖分+线段树】

    裸的树链剖分+线段树 但是要注意一个地方--我WA了好几次才发现取完相反数之后max值和min值是要交换的-- #include<iostream> #include<cstdio& ...

随机推荐

  1. bzoj1997: [Hnoi2010]Planar

    2-SAT. 首先有平面图定理 m<=3*n-6,如果不满足这条件肯定不是平面图,直接退出. 然后构成哈密顿回路的边直接忽略. 把哈密顿回路当成一个圆, 如果俩条边交叉(用心去感受),只能一条边 ...

  2. LA 2572 (求可见圆盘的数量) Kanazawa

    题意: 把n个圆盘依次放到桌面上,按照放置的先后顺序给出这n个圆盘的圆心和半径,输出有多少个圆盘可见(即未被全部覆盖). 分析: 题中说对输入数据进行微小扰动后答案不变. 所露出的部分都是由若干小圆弧 ...

  3. hdu 4607 Park Visit(树上最长链)

    求树上最长链:两遍搜索. 第一次从树上任意点开始,最远点必然是某一条最长链上的端点u. 第二次从u开始,最远点即该最长链的另一端点. 先在最长链上走,不足再去走支链. 把询问数m错打成n,狠狠wa了一 ...

  4. 05day2

    05day1 没什么可说,一道模拟水题,两道裸的模板题.05day2 是几天以来最难的一次.   圆排列 动态规划 [问题描述] 有 N 个人顺时针围在一圆桌上开会,他们对身高很敏感. 因此决定想使得 ...

  5. 02day1

    淘汰赛制 递推 [问题描述] 淘汰赛制是一种极其残酷的比赛制度.2^n名选手分别标号1,2,3,…,2^n-1,2^n,他们将要参加n轮的激烈角逐.每一轮中,将所有参加该轮的选手按标号从小到大排序后, ...

  6. 【C#学习笔记】Dictionary容器使用

    using System; using System.Collections.Generic; namespace ConsoleApplication { class Program { stati ...

  7. 查询MySQL锁等待的语句

    select 'Blocker' role,    p.id,    p.user,    left(p.host, locate(':', p.host) - 1) host,    tx.trx_ ...

  8. 开学了!这些Linux认证你要知道。

    导读 大家好,今天我们将认识一些非常有价值的全球认可的Linux认证.Linux认证是不同的Linux专业机构在全球范围内进行的认证程序.Linux认证可以让Linux专业人才可以在服务器领域或相关公 ...

  9. EasyHook远注简单监控示例 z

    http://www.csdn 123.com/html/itweb/20130827/83559_83558_83544.htm 免费开源库EasyHook(inline hook),下面是下载地址 ...

  10. <转>Python 多线程的单cpu与cpu上的多线程的区别

    你对Python 多线程有所了解的话.那么你对python 多线程在单cpu意义上的多线程与多cpu上的多线程有着本质的区别,如果你对Python 多线程的相关知识想有更多的了解,你就可以浏览我们的文 ...