题意

对一个树上维护两种操作,一种是把x到y间的点都染成c色,另一种是求x到y间的点有多少个颜色块,比如112221由“11”,“222”,“1”三块组成。

思路

这题的关键是要如何维护这个颜色块,我们可以利用线段树,记录每个区间的块数,区间左端点,区间右端点的颜色。合并中如果两个区间相邻点颜色相同,个数要减去1.
查询也是一样的,链与链间的相邻点也要考虑清楚。

#include <algorithm>
#include <iterator>
#include <iostream>
#include <cstring>
#include <cstdlib>
#include <iomanip>
#include <bitset>
#include <cctype>
#include <cstdio>
#include <string>
#include <vector>
#include <stack>
#include <cmath>
#include <queue>
#include <list>
#include <map>
#include <set>
#include <cassert> /* ⊂_ヽ
  \\ Λ_Λ 来了老弟
   \('ㅅ')
    > ⌒ヽ
   /   へ\
   /  / \\
   レ ノ   ヽ_つ
  / /
  / /|
 ( (ヽ
 | |、\
 | 丿 \ ⌒)
 | |  ) /
'ノ )  Lノ */ using namespace std;
#define lson (l , mid , rt << 1)
#define rson (mid + 1 , r , rt << 1 | 1)
#define debug(x) cerr << #x << " = " << x << "\n";
#define pb push_back
#define pq priority_queue typedef long long ll;
typedef unsigned long long ull;
//typedef __int128 bll;
typedef pair<ll ,ll > pll;
typedef pair<int ,int > pii;
typedef pair<int,pii> p3; //priority_queue<int> q;//这是一个大根堆q
//priority_queue<int,vector<int>,greater<int> >q;//这是一个小根堆q
#define fi first
#define se second
//#define endl '\n' #define boost ios::sync_with_stdio(false);cin.tie(0)
#define rep(a, b, c) for(int a = (b); a <= (c); ++ a)
#define max3(a,b,c) max(max(a,b), c);
#define min3(a,b,c) min(min(a,b), c); const ll oo = 1ll<<;
const ll mos = 0x7FFFFFFF; //
const ll nmos = 0x80000000; //-2147483648
const int inf = 0x3f3f3f3f;
const ll inff = 0x3f3f3f3f3f3f3f3f; //
const ll mod = ;
const double esp = 1e-;
const double PI=acos(-1.0);
const double PHI=0.61803399; //黄金分割点
const double tPHI=0.38196601; template<typename T>
inline T read(T&x){
x=;int f=;char ch=getchar();
while (ch<''||ch>'') f|=(ch=='-'),ch=getchar();
while (ch>=''&&ch<='') x=x*+ch-'',ch=getchar();
return x=f?-x:x;
} inline void cmax(int &x,int y){if(x<y)x=y;}
inline void cmax(ll &x,ll y){if(x<y)x=y;}
inline void cmin(int &x,int y){if(x>y)x=y;}
inline void cmin(ll &x,ll y){if(x>y)x=y;} /*-----------------------showtime----------------------*/ const int maxn = 1e5+;
int a[maxn],b[maxn];
int dp[maxn],sz[maxn],fa[maxn],son[maxn];
vector<int>mp[maxn]; void dfs1(int u,int f,int deep){
dp[u] = deep;
fa[u] = f;
sz[u] = ;
int mx = ;
for(int i=; i<mp[u].size(); i++){
int v = mp[u][i];
if(v == f) continue;
dfs1(v, u, deep+);
sz[u] += sz[v];
if(sz[v] > mx) {mx = sz[v], son[u] = v;}
}
} int top[maxn],id[maxn],cnt = ;
void dfs2(int u,int f,int topf){
top[u] = topf;
id[u] = ++cnt;
b[cnt] = a[u];
if(son[u])dfs2(son[u], u, topf);
for(int i=; i<mp[u].size(); i++){
int v = mp[u][i];
if(v == f || v == son[u]) continue;
dfs2(v, u, v);
}
} int tag[maxn<<],lazy[maxn<<],ly[maxn<<],rz[maxn<<];
void pushup(int rt){
tag[rt] = tag[rt<<] + tag[rt<<|];
rz[rt] = rz[rt<<];
ly[rt] = ly[rt<<|];
if(ly[rt<<] == rz[rt<<|])tag[rt] --;
}
void build(int l,int r,int rt){
if(l == r){
tag[rt] = ;
ly[rt] = rz[rt] = b[l];
return ;
}
int mid = (l + r) >> ;
build(l, mid, rt<<);
build(mid+,r,rt<<|);
pushup(rt);
// cout<<l<<" "<<r<<" "<<rz[rt] << " " << ly[rt]<<endl;
}
void pushdown(int l,int r,int rt){
tag[rt<<] = tag[rt<<|] = ;
ly[rt<<] = rz[rt<<] = lazy[rt];
ly[rt<<|] = rz[rt<<|] = lazy[rt];
lazy[rt<<] = lazy[rt<<|] = lazy[rt];
lazy[rt] = ;
}
void update(int L, int R, int c, int l, int r,int rt){
if(l >= L && r <= R){
tag[rt] = ;
ly[rt] = rz[rt] = c;
lazy[rt] = c;
return;
}
int mid = (l + r) >> ;
if(lazy[rt]) pushdown(l, r, rt);
if(mid >= L) update(L, R, c, l, mid, rt<<);
if(mid < R) update(L,R,c,mid+,r,rt<<|);
pushup(rt);
}
int n,m;
void solve(int x,int y,int c){
while(top[x] != top[y]){
if(dp[top[x]] < dp[top[y]]) swap(x, y);
update(id[top[x]], id[x], c, , n, );
x = fa[top[x]];
}
if(dp[x] > dp[y]) swap(x, y);
update(id[x], id[y], c, , n, );
} int query(int L,int R, int l,int r,int rt,int &tmpl,int &tmpr){
if(l >= L && r<= R){
if(l == L) tmpl = rz[rt];
if(r == R) tmpr = ly[rt]; return tag[rt];
}
int mid = (l + r) >> ;
if(lazy[rt])pushdown(l, r, rt);
int res = ;
int ql = -, qr = -;
if(mid >= L) {
res += query(L, R, l, mid, rt<<,tmpl,tmpr);
ql = ly[rt<<];
}
if(mid < R){
res += query(L, R, mid +, r, rt<<|,tmpl,tmpr);
qr = rz[rt<<|];
}
if(ql == qr && ql != -) res --;
pushup(rt);
return res;
}
int cal(int x,int y){
int res = ,lax = -,lay=-; while(top[x] != top[y]){
int tmpl = -,tmpr=-;
if(dp[top[x]] > dp[top[y]]) {
res += query(id[top[x]], id[x], , n, , tmpl, tmpr);//tmp,flag 1,r
if(lax == tmpr) res--;
lax = tmpl;
x = fa[top[x]];
}
else {
res += query(id[top[y]], id[y], , n, ,tmpl,tmpr);
if(lay == tmpr) res--;
lay = tmpl;
y = fa[top[y]];
} // cout<<tmpl<<" !! "<<tmpr<<endl;
} if(dp[x] > dp[y]){
int tmpl = -,tmpr=-;
res += query(id[y], id[x], , n, ,tmpl,tmpr);
if(tmpr == lax) res--;
if(tmpl == lay) res--;
}
else {
int tmpl = -,tmpr=-;
res += query(id[x], id[y], , n, ,tmpl,tmpr);
if(tmpl == lax) res--;
if(tmpr == lay) res--;
} return res;
}
int main(){
scanf("%d%d", &n, &m);
rep(i, , n) scanf("%d", &a[i]);
rep(i, , n-) {
int u,v;
scanf("%d%d", &u, &v);
mp[u].pb(v);
mp[v].pb(u);
}
dfs1(, , );
dfs2(, , );
build(, n, ); while(m--){
char str[];
scanf("%s", str);
if(str[] == 'C') {
int x,y,z;
scanf("%d%d%d", &x, &y, &z);
solve(x, y, z);
}
else {
int x,y;
scanf("%d%d", &x, &y);
printf("%d\n", cal (x,y));
} }
return ;
}

P2486 [SDOI2011]染色 维护区间块数 树链剖分的更多相关文章

  1. bzoj 2243: [SDOI2011]染色 线段树区间合并+树链剖分

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

  2. P2486 [SDOI2011]染色 区间合并+树链剖分(加深对线段树的理解)

    #include<bits/stdc++.h> using namespace std; ; struct node{ int l,r,cnt,lazy; node(,,,):l(l1), ...

  3. P2486 [SDOI2011]染色 区间合并+树链剖分(加深对线段树的理解)

    #include<bits/stdc++.h> using namespace std; ; struct node{ int l,r,cnt,lazy; node(,,,):l(l1), ...

  4. 2020牛客NOIP赛前集训营-提高组(第三场) C - 牛半仙的妹子Tree (树链剖分)

    昨天教练问我:你用树剖做这道题,怎么全部清空状态呢?    我:???不是懒标记就完了???    教练:树剖不是要建很多棵线段树吗,不止log个,你要一个一个清?    我:为什么要建很多棵线段树? ...

  5. luogu题解 P3950部落冲突--树链剖分

    题目链接 https://www.luogu.org/problemnew/show/P3950 分析 大佬都用LCT,我太弱只会树链剖分 一个很裸的维护边权树链剖分题.按照套路,对于一条边\(< ...

  6. Luogu P2486 [SDOI2011]染色(树链剖分+线段树合并)

    Luogu P2486 [SDOI2011]染色 题面 题目描述 输入输出格式 输入格式: 输出格式: 对于每个询问操作,输出一行答案. 输入输出样例 输入样例: 6 5 2 2 1 2 1 1 1 ...

  7. 洛谷 P2486 [SDOI2011]染色 树链剖分

    目录 题面 题目链接 题目描述 输入输出格式 输入格式 输出格式 输入输出样例 输入样例: 输出样例: 说明 思路 PushDown与Update Q AC代码 总结与拓展 题面 题目链接 P2486 ...

  8. bzoj 2243: [SDOI2011]染色 (树链剖分+线段树 区间合并)

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

  9. P2486 [SDOI2011]染色(树剖)区间覆盖+区间的连续段

    https://www.luogu.org/problemnew/show/P2486 值的一看https://www.cnblogs.com/Tony-Double-Sky/p/9283262.ht ...

随机推荐

  1. 【iOS】CGContextSaveGState: invalid context 0x0. If you want to see the backtrace, please set CG_CONTEXT_SHOW_BACKTRACE environmental variable

    CGContextSaveGState: invalid context 0x0. If you want to see the backtrace, please set CG_CONTEXT_SH ...

  2. Jquery.form异步上传文件常见问题解决

    Jquery.form常用方法我就不多说,主要说一下在使用过程中碰到的问题 1.提示 “xxxx” is not define 或者"xxx" is not a function ...

  3. Redis——发布和订阅

    发布与订阅(又称pub/sub),订阅者(listener)负责订阅频道(channel),发送者(publisher)负责向频道发送二进制字符串消息(binary string message).每 ...

  4. js实现图片上传方法

    知识点 onchange事件 循环 封装函数 ajax php Javascript代码 //找到元素 var file=document.getElementById("file" ...

  5. 编程杂谈——Non-breaking space

    近日,意外地遇上件不寻常的事情.在解析PDF文件,读取其中内容的时候,对某一文件的处理,始终无法达到预期的效果. 解析方法如下: public void Parse(string value) { i ...

  6. Javascript中,实现十大排序方法之一(冒泡排序及其优化设想)

    冒泡排序的Javascript实现 首先定义一个取值范围在(0~100000)之间的随机值的长度为10万的数组, function bubbleSort(arr) { console.time('冒泡 ...

  7. spring-boot-plus快速开始 Quick Start(一)

    spring-boot-plus快速开始 Quick Start 1. clone项目到本地 shell script git clone git@github.com:geekidea/spring ...

  8. C语言编程入门之--第五章C语言基本运算和表达式-part3

    5.3  挑几个运算符来讲 常用的运算符除了加减乘除(+-*/)外,还有如下: 注意:以下运算符之间用逗号隔开,C语言中也有逗号运算符,这里不讲逗号运算符. 1. 赋值运算符 =,+=,*= 2. 一 ...

  9. 你是否真的了解全局解析锁(GIL)

    关于我 一个有思想的程序猿,终身学习实践者,目前在一个创业团队任team lead,技术栈涉及Android.Python.Java和Go,这个也是我们团队的主要技术栈. Github:https:/ ...

  10. iOS 11 变化

    首先我是开发者,更关心对技术的影响,我又需要关注.学习哪些技术,猫神的文章:http://www.cocoachina.com/ios/20170607/19457.html 介绍了 ******** ...