染色(bzoj 2243)
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<cstdio> #include<iostream> #define N 100010 using namespace std; int a[N],head[N],fa[N],son[N],dep[N],pos[N],top[N],lco[N*4],rco[N*4],sum[N*4],tag[N*4],n,m,sz; struct node{ int to,pre; };node e[N*2]; void add(int i,int x,int y){ e[i].to=y; e[i].pre=head[x]; head[x]=i; } void dfs1(int x){ son[x]=1; for(int i=head[x];i;i=e[i].pre){ int v=e[i].to; if(fa[x]==v) continue; fa[v]=x;dep[v]=dep[x]+1; dfs1(v); son[x]+=son[v]; } } void dfs2(int x,int chain){ ++sz;pos[x]=sz;top[x]=chain;int k=0,maxn=0; for(int i=head[x];i;i=e[i].pre) if(fa[x]!=e[i].to&&son[e[i].to]>maxn){ k=e[i].to;maxn=son[e[i].to]; } if(!k) return; dfs2(k,chain); for(int i=head[x];i;i=e[i].pre) if(fa[x]!=e[i].to&&e[i].to!=k) dfs2(e[i].to,e[i].to); } void pushup(int k){ lco[k]=lco[k*2];rco[k]=rco[k*2+1]; sum[k]=sum[k*2]+sum[k*2+1]; if(rco[k*2]==lco[k*2+1])sum[k]--; } void pushdown(int k){ if(!tag[k]) return; tag[k*2]=tag[k*2+1]=tag[k]; lco[k*2]=lco[k*2+1]=tag[k]; rco[k*2]=rco[k*2+1]=tag[k]; sum[k*2]=sum[k*2+1]=1; tag[k]=0; } void change(int l,int r,int k,int x,int y,int v){ if(l>=x&&r<=y){ tag[k]=lco[k]=rco[k]=v; sum[k]=1; return; } pushdown(k); int mid=l+r>>1; if(x<=mid) change(l,mid,k*2,x,y,v); if(y>mid) change(mid+1,r,k*2+1,x,y,v); pushup(k); } int query(int l,int r,int k,int x,int y){ if(l==x&&r==y)return sum[k]; pushdown(k); int mid=l+r>>1; if(y<=mid) return query(l,mid,k*2,x,y); else if(x>mid) return query(mid+1,r,k*2+1,x,y); else { int ans=query(l,mid,k*2,x,mid)+query(mid+1,r,k*2+1,mid+1,y); if(rco[k*2]==lco[k*2+1]) ans--; return ans; } } int find(int l,int r,int k,int x){ if(l==r)return lco[k]; pushdown(k); int mid=l+r>>1; if(x<=mid) return find(l,mid,k*2,x); else return find(mid+1,r,k*2+1,x); } void xiugai(int x,int y,int v){ while(top[x]!=top[y]){ if(dep[top[x]]<dep[top[y]])swap(x,y); change(1,n,1,pos[top[x]],pos[x],v); x=fa[top[x]]; } if(dep[x]>dep[y]) swap(x,y); change(1,n,1,pos[x],pos[y],v); } int qiuhe(int x,int y){ int ans=0; while(top[x]!=top[y]){ if(dep[top[x]]<dep[top[y]])swap(x,y); ans+=query(1,n,1,pos[top[x]],pos[x]); if(find(1,n,1,pos[fa[top[x]]])==find(1,n,1,pos[top[x]])) ans--; x=fa[top[x]]; } if(dep[x]>dep[y]) swap(x,y); ans+=query(1,n,1,pos[x],pos[y]); return ans; } int main(){ freopen("jh.in","r",stdin); scanf("%d%d",&n,&m); for(int i=1;i<=n;i++)scanf("%d",&a[i]); for(int i=1;i<n;i++){ int x,y;scanf("%d%d",&x,&y); add(i*2-1,x,y);add(i*2,y,x); } dfs1(1);dfs2(1,1); for(int i=1;i<=n;i++)change(1,n,1,pos[i],pos[i],a[i]); char opt[10]; for(int i=1;i<=m;i++){ int x,y,v; scanf("%s%d%d",opt,&x,&y); if(opt[0]=='C'){ scanf("%d",&v); xiugai(x,y,v); } else printf("%d\n",qiuhe(x,y)); } return 0; }