[bzoj2243] [SDOI2011]染色
阿新 • • 發佈:2018-12-19
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
Sample Output
3
1
2
HINT
數N<=10^5,運算元M<=10 ^5,所有的顏色C為整數且在[0, 10^9]之間。
solution
\(LCT\),挺板子的,記錄區間的左右端點的顏色,然後注意\(reverse\)的時候要\(swap(lcol,rcol)\)
樹鏈剖分也可以寫,應該會快一些?但是複雜度高。
#include<bits/stdc++.h> using namespace std; void read(int &x) { x=0;int f=1;char ch=getchar(); for(;!isdigit(ch);ch=getchar()) if(ch=='-') f=-f; for(;isdigit(ch);ch=getchar()) x=x*10+ch-'0';x*=f; } void print(int x) { if(x<0) putchar('-'),x=-x; if(!x) return ;print(x/10),putchar(x%10+48); } void write(int x) {if(!x) putchar('0');else print(x);putchar('\n');} const int maxn = 1e5+1; int col[maxn]; struct Link_Cut_Tree { int fa[maxn],son[maxn][2],lcol[maxn],rcol[maxn],rev[maxn],cov[maxn],sum[maxn],sta[maxn]; void update(int x) { lcol[x]=son[x][0]?lcol[son[x][0]]:col[x]; rcol[x]=son[x][1]?rcol[son[x][1]]:col[x]; if(son[x][0]&&son[x][1]) sum[x]=sum[son[x][0]]+sum[son[x][1]]+1-(col[x]==rcol[son[x][0]])-(col[x]==lcol[son[x][1]]); else if(son[x][0]) sum[x]=sum[son[x][0]]+(col[x]!=rcol[son[x][0]]); else if(son[x][1]) sum[x]=sum[son[x][1]]+(col[x]!=lcol[son[x][1]]); else sum[x]=1; } void push_rev(int x) {if(x) rev[x]^=1,swap(son[x][0],son[x][1]),swap(lcol[x],rcol[x]);} void push_cov(int x,int c) {if(x) col[x]=cov[x]=lcol[x]=rcol[x]=c,sum[x]=1;} void pushdown(int x) { if(rev[x]) rev[x]^=1,push_rev(son[x][0]),push_rev(son[x][1]); if(cov[x]) push_cov(son[x][0],cov[x]),push_cov(son[x][1],cov[x]),cov[x]=0; } int which(int x) {return son[fa[x]][1]==x;} int is_root(int x) {return son[fa[x]][0]!=x&&son[fa[x]][1]!=x;} void rotate(int x) { int f=fa[x],ff=fa[f],w=which(x); if(!is_root(f)) son[ff][son[ff][1]==f]=x; fa[x]=ff,fa[f]=x,son[f][w]=son[x][w^1],fa[son[x][w^1]]=f,son[x][w^1]=f; update(f),update(x); } void splay(int x) { int t=x,top=0; while(!is_root(t)) sta[++top]=t,t=fa[t];sta[++top]=t; while(top) pushdown(sta[top--]); while(!is_root(x)) { int y=fa[x],z=fa[y]; if(!is_root(y)) rotate(((son[y][1]==x)^(son[z][1]==y))?x:y); rotate(x); }update(x); } void access(int x) { for(int t=0;x;t=x,x=fa[x]) splay(x),son[x][1]=t,update(x); } void make_root(int x) { access(x),splay(x),push_rev(x); } void link(int x,int y) { make_root(x),fa[x]=y; } void split(int x,int y) { make_root(x),access(y),splay(y); } void modify(int x,int y,int c) { split(x,y),push_cov(y,c); } int query(int x,int y) { split(x,y);return sum[y]; } }LCT; int main() { int n,m;read(n),read(m); for(int i=1;i<=n;i++) read(col[i]); for(int i=1,x,y;i<n;i++) read(x),read(y),LCT.link(x,y); for(int i=1;i<=m;i++) { char s[4];scanf("%s",s+1);int x,y,z;read(x),read(y); if(s[1]=='C') read(z),LCT.modify(x,y,z); else write(LCT.query(x,y)); } return 0; }