BZOJ 2243: [SDOI2011]染色 树链剖分+线段树区间合并
2243: [SDOI2011]染色
Description
给定一棵有n个节点的无根树和m个操作,操作有2类:
1、将节点a到节点b路径上所有点都染成颜色c;
2、询问节点a到节点b路径上的颜色段数量(连续相同颜色被认为是同一段),如“112221”由3段组成:“11”、“222”和“1”。
请你写一个程序依次完成这m个操作。
Input
第一行包含2个整数n和m,分别表示节点数和操作数;
第二行包含n个正整数表示n个节点的初始颜色
下面 行每行包含两个整数x和y,表示x和y之间有一条无向边。
下面 行每行描述一个操作:
“C a b c”表示这是一个染色操作,把节点a到节点b路径上所有点(包括a和b)都染成颜色c;
“Q a b”表示这是一个询问操作,询问节点a到节点b(包括a和b)路径上的颜色段数量。
Output
对于每个询问操作,输出一行答案。
Sample Input
6 5
2 2 1 2 1 1
1 2
1 3
2 4
2 5
2 6
Q 3 5
C 2 1 1
Q 3 5
C 5 1 2
Q 3 5
2 2 1 2 1 1
1 2
1 3
2 4
2 5
2 6
Q 3 5
C 2 1 1
Q 3 5
C 5 1 2
Q 3 5
Sample Output
3
1
2
1
2
HINT
数N<=10^5,操作数M<=10^5,所有的颜色C为整数且在[0, 10^9]之间。
题解:
树链剖分后,在相应的标号上进行线段树操作
#include<bits/stdc++.h> using namespace std; #pragma comment(linker, "/STACK:102400000,102400000") #define ls i<<1 #define rs ls | 1 #define mid ((ll+rr)>>1) #define pii pair<int,int> #define MP make_pair typedef long long LL; const long long INF = 1e18+1LL; const double Pi = acos(-1.0); const int N = 5e5+10, M = 1e3+20, mod = 1e9+7, inf = 2e9; int dep[N],head[N],t=1,sz[N],fa[N],indexS,top[N],pos[N]; struct ss{int to,next;}e[N*2]; int n; void add(int u,int v) {e[t].to = v;e[t].next = head[u];head[u] = t++;} void dfs(int u) { sz[u] = 1; dep[u] = dep[fa[u]] + 1; for(int i = head[u]; i; i = e[i].next) { int to = e[i].to; if(to == fa[u]) continue; fa[to] = u; dfs(to); sz[u] += sz[to]; } } void dfs(int u,int chain) { int k = 0; pos[u] = ++indexS; top[u] = chain; for(int i = head[u]; i; i = e[i].next) { int to = e[i].to; if(dep[to] > dep[u] && sz[to] > sz[k]) k = to; } if(k == 0) return ; dfs(k,chain); for(int i = head[u]; i; i = e[i].next) { int to = e[i].to; if(dep[to] > dep[u] && k != to) dfs(to,to); } } LL lx[N],rx[N],mx[N],sum[N],lazy[N],fposs[N]; void push_up(int i) { sum[i] = sum[ls] + sum[rs]; if(rx[ls] == lx[rs]) sum[i]-=1; lx[i] = lx[ls];rx[i] = rx[rs]; } void build(int i,int ll,int rr) { if(ll == rr) { lx[i] = fposs[ll]; rx[i] = fposs[ll]; sum[i] = 1; return ; } build(ls,ll,mid),build(rs,mid+1,rr); push_up(i); } void push_down(int i,int ll,int rr) { if(lazy[i] && ll != rr) { lazy[ls] = lazy[i]; lazy[rs] = lazy[i]; lx[ls] = lazy[i]; rx[ls] = lazy[i]; lx[rs] = lazy[i]; rx[rs] = lazy[i]; sum[ls] = 1; sum[rs] = 1; lazy[i] = 0; } } void update(int i,int ll,int rr,int x,int y,int c) { push_down(i,ll,rr); if(ll == x && rr == y) { lazy[i] = c; lx[i] = c; rx[i] = c; sum[i] = 1; return ; } if(y <= mid) update(ls,ll,mid,x,y,c); else if(x > mid) update(rs,mid+1,rr,x,y,c); else { update(ls,ll,mid,x,mid,c); update(rs,mid+1,rr,mid+1,y,c); } push_up(i); } void change(int x,int y,int c) { while(top[x] != top[y]) { if(dep[top[x]] < dep[top[y]]) swap(x,y); update(1,1,n,pos[top[x]],pos[x],c); x = fa[top[x]]; } if(dep[x] > dep[y]) swap(x,y); update(1,1,n,pos[x],pos[y],c); } int query(int i,int ll,int rr,int x,int y) { push_down(i,ll,rr); if(ll == x && rr == y) return sum[i]; if(y <= mid) return query(ls,ll,mid,x,y); else if(x > mid) return query(rs,mid+1,rr,x,y); else return (query(ls,ll,mid,x,mid) + query(rs,mid+1,rr,mid+1,y) - (lx[rs] == rx[ls])); push_up(i); } int color(int i,int ll,int rr,int x) { push_down(i,ll,rr); if(ll == rr) return lx[i]; if(x <= mid) return color(ls,ll,mid,x); else return color(rs,mid+1,rr,x); push_up(i); } int query(int x,int y) { int res = 0,lastx = -1,lasty = -1; while(top[x] != top[y]) { if(dep[top[x]] > dep[top[y]]) { res += query(1,1,n,pos[top[x]],pos[x]); if(color(1,1,n,pos[x]) == lastx) res--; lastx = color(1,1,n,pos[top[x]]); x = fa[top[x]]; } else { res += query(1,1,n,pos[top[y]],pos[y]); if(color(1,1,n,pos[y]) == lasty) res--; lasty = color(1,1,n,pos[top[y]]); y = fa[top[y]]; } } if(dep[x] < dep[y])res += query(1,1,n,pos[x],pos[y]); else res += query(1,1,n,pos[y],pos[x]); if(color(1,1,n,pos[x]) == lastx) res--; if(color(1,1,n,pos[y]) == lasty) res--; return res; } int Q,a[N],x,y; char ch[N]; int main() { scanf("%d%d",&n,&Q); for(int i = 1; i <= n; ++i) scanf("%d",&a[i]); for(int i = 1; i < n; ++i) { scanf("%d%d",&x,&y); add(x,y); add(y,x); } dfs(1); dfs(1,1); for(int i = 1; i <= n; ++i) fposs[pos[i]] = a[i]; build(1,1,n); while(Q--) { int a,b,c; scanf("%s",ch); if(ch[0] == 'Q') { scanf("%d%d",&a,&b); printf("%d\n",query(a,b)); }else { scanf("%d%d%d",&a,&b,&c); change(a,b,c); } } return 0; } /* 6 5 2 2 1 2 1 1 1 2 1 3 2 4 2 5 2 6 Q 3 5 C 2 1 1 Q 3 5 C 5 1 2 Q 3 5 */