[BZOJ2243][SDOI2011]染色
2243: [SDOI2011]染色
Time Limit: 20 Sec Memory Limit: 512 MBSubmit: 10933 Solved: 4237
[Submit][Status][Discuss]
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]之间。
Source
试题分析
毒瘤题目,$A$掉了是真的开心啊!!!
建立线段树
其实做法十分显然,我们考虑树链剖分,对于线段树上我们维护在$[l,r]$区间内的颜色段$(ans(k))$,而要求$ans(k)$我们需要左右节点的$ans,ans(k<<1),ans(k<<1|1)$,并且我们需要判断合并时若$mid$与$mid+1$同颜色便需要$-1$,而对于任意都$ans(k)=ans(k<<1)+ans(k<<1|1)$。
在路径上覆盖颜色(即$1$操作)
考虑线段树覆盖颜色,记录一下次条线段是否被覆盖。
查询颜色数量(即$2$操作)
我们在建立线段树时已经讨论了$-1$的问题,而$-1$在树上维护时我们需要去求当现在要求$(u,v)$,$(deep(u)<deep(v))$时,我们需要查询路径中有没有$v$的儿子,有的话判断两个点的颜色是否相同,若相同就$-1$.
然后就慢慢垒吧。
#include<iostream> #include<cstring> #include<cstdio> #include<algorithm> using namespace std; inline int read(){ int f=1,ans=0;char c=getchar(); while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();} while(c>='0'&&c<='9'){ans=ans*10+c-'0';c=getchar();} return f*ans; } const int N=500001; struct node{ int u,v,nex; }x[N<<1]; int val[N],deep[N],fa[N],m,size[N],son[N],top[N],head[N],cnt,seg[N],id[N],n; void add(int u,int v){ x[cnt].u=u,x[cnt].v=v,x[cnt].nex=head[u],head[u]=cnt++; } void dfs1(int f,int fath){ size[f]=1; deep[f]=deep[fath]+1; fa[f]=fath; for(int i=head[f];i!=-1;i=x[i].nex){ if(x[i].v==fath) continue; dfs1(x[i].v,f); size[f]+=size[x[i].v]; if(size[son[f]]<size[x[i].v]) son[f]=x[i].v; }return; } void dfs2(int f,int fath){ if(son[f]){ top[son[f]]=top[f]; seg[son[f]]=++seg[0]; id[seg[0]]=son[f]; dfs2(son[f],f); } for(int i=head[f];i!=-1;i=x[i].nex){ if(x[i].v==fath||x[i].v==son[f]) continue; seg[x[i].v]=++seg[0]; id[seg[0]]=x[i].v; top[x[i].v]=x[i].v; dfs2(x[i].v,f); } } int ans[N<<2],flag[N]; int lst,Ans; struct segment_tree{ void pushdown(int k,int l,int r){ if(flag[k]==-1) return; int mid=l+r>>1; ans[k<<1]=1;ans[k<<1|1]=1; flag[k<<1]=flag[k],flag[k<<1|1]=flag[k]; int color=flag[k]; val[id[l]]=color,val[id[mid]]=color,val[id[mid+1]]=color,val[id[r]]=color; flag[k]=-1; return; } void build(int k,int l,int r){ if(l==r){ans[k]=1;return;} int mid=l+r>>1; build(k<<1,l,mid),build(k<<1|1,mid+1,r); ans[k]=ans[k<<1]+ans[k<<1|1]; if(val[id[mid]]==val[id[mid+1]]) ans[k]--; return; } void change(int k,int l,int r,int x,int y,int col){ if(x<=l&&r<=y){flag[k]=col;ans[k]=1;val[id[l]]=col,val[id[r]]=col;return;} int mid=l+r>>1; pushdown(k,l,r); if(x<=mid) change(k<<1,l,mid,x,y,col); if(mid<y) change(k<<1|1,mid+1,r,x,y,col); ans[k]=ans[k<<1]+ans[k<<1|1]; if(val[id[mid]]==val[id[mid+1]]) ans[k]--; return; } int query_color(int k,int l,int r,int x,int y){ if(l==r) return val[id[l]]; pushdown(k,l,r); int mid=l+r>>1,res=0; if(x<=mid) res+=query_color(k<<1,l,mid,x,y); if(mid<y) res+=query_color(k<<1|1,mid+1,r,x,y); ans[k]=ans[k<<1]+ans[k<<1|1]; if(val[id[mid]]==val[id[mid+1]]) ans[k]--; return res; } void query(int k,int l,int r,int x,int y){ if(x<=l&&r<=y){ Ans+=ans[k]; if(lst!=-1) if(query_color(1,1,n,lst,lst)==query_color(1,1,n,l,l)) Ans--; lst=r; return; } pushdown(k,l,r); int mid=l+r>>1; if(x<=mid) query(k<<1,l,mid,x,y); if(mid<y) query(k<<1|1,mid+1,r,x,y); } int Query(int x,int y){ Ans=0; lst=-1; query(1,1,n,seg[x],seg[y]); return Ans; } }segment; char str[3]; void change(int x,int y,int color){ int fx=top[x],fy=top[y]; while(fx!=fy){ if(deep[fx]<deep[fy]) swap(x,y),swap(fx,fy); segment.change(1,1,seg[0],seg[fx],seg[x],color); x=fa[fx],fx=top[x]; } if(deep[x]>deep[y]) swap(x,y); segment.change(1,1,seg[0],seg[x],seg[y],color); return; } int find(int x,int sonx,int sony){ if(sonx==-1&&sony==-1) return 0; if(sonx==-1){ if(fa[sony]==x) return sony; return 0; } if(sony==-1){ if(fa[sonx]==x) return sonx; return 0; } if(fa[sonx]==x) return sonx; if(fa[sony]==x) return sony; return 0; } int query(int x,int y){ int ans=0,fx=top[x],fy=top[y],sonx=-1,sony=-1; int tot=0; while(fx!=fy){ ++tot; if(deep[fx]<deep[fy]) swap(x,y),swap(fx,fy); ans+=segment.Query(fx,x); int k=find(x,sonx,sony); if(k){ int col1=segment.query_color(1,1,seg[0],seg[x],seg[x]); int col2=segment.query_color(1,1,seg[0],seg[k],seg[k]); if(col1==col2) ans--; if(sonx==k) sonx=fx; else sony=fx; }else{ if(sonx==-1) sonx=fx; else sony=fx; } x=fa[fx],fx=top[x]; } if(deep[x]>deep[y]) swap(x,y); int k1=find(x,sonx,sony); int k2=0; if(x!=y||(sonx!=-1&&sony!=-1&&sonx!=sony)) k2=find(y,sony,sonx); if(k1){ if(sonx==k1) k1=sonx; else k1=sony; } if(k2){ if(sonx==k2) k2=sonx; else k2=sony; } ans+=segment.Query(x,y); if(k1){ int col1=segment.query_color(1,1,seg[0],seg[x],seg[x]); int col2=segment.query_color(1,1,seg[0],seg[k1],seg[k1]); if(col1==col2) ans--; } if(k2){ int col1=segment.query_color(1,1,seg[0],seg[y],seg[y]); int col2=segment.query_color(1,1,seg[0],seg[k2],seg[k2]); if(col1==col2) ans--; }return ans; } int main(){ memset(flag,-1,sizeof(flag)); memset(head,-1,sizeof(head)); n=read(),m=read(); for(int i=1;i<=n;i++) val[i]=read(); for(int i=1;i<n;i++){ int u=read(),v=read(); add(u,v),add(v,u); } dfs1(1,0); seg[0]=seg[1]=id[1]=top[1]=1; dfs2(1,0); segment.build(1,1,n); for(int i=1;i<=m;i++){ scanf("%s",str+1); if(str[1]=='C'){ int x=read(),y=read(),col=read(); change(x,y,col); }else{ int x=read(),y=read(); printf("%d\n",query(x,y)); } } return 0; }