[SDOI2011]染色
题目描述
输入输出格式
输入格式:
输出格式:
对于每个询问操作,输出一行答案。
输入输出样例
说明
题解
这道题目不是很难做,但是很难调
怎么个难调法
1.跳lca时要注意两条链并入时的颜色是否相同
2.询问有多少个颜色块的query中,l,r 区间不是平常的线段树,我们也要考虑l,r区间的左右端点颜色是否相同。
3,要处理的东西贼多
#include<cstdio> #include<cstring> #include<cmath> #include<algorithm> #include<iostream> using namespace std; const int N=500001; int n,m,tot,num,head[N],size[N],son[N],ch[N]; int color[N*4],top[N],dep[N*4],ll[N*4],rr[N*4],sum[N*4],a[N],l[N],fa[N],lazy[N*4]; struct node{ int next,v,to; }e[N*2]; int read() { int x=0,w=1;char ch=getchar(); while(ch>'9'||ch<'0'){if(ch=='-')w=-1;ch=getchar();} while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar(); return x*w; } void add(int from,int to) { num++; e[num].to=to; // e[num].v=v; e[num].next=head[from]; head[from]=num; } void dfs1(int x,int ff) { size[x]=1; for(int i=head[x];i;i=e[i].next) { int v=e[i].to; if(!dep[v]) { dep[v]=dep[x]+1; fa[v]=x; dfs1(v,x); size[x]+=size[v]; if(size[son[x]]<size[v])son[x]=v; } } return; } void dfs2(int x,int fx) { l[x]=++tot;a[tot]=ch[x];top[x]=fx; if(son[x])dfs2(son[x],fx); for(int i=head[x];i;i=e[i].next) { int v=e[i].to; if(v!=fa[x]&&v!=son[x]) { dfs2(v,v); } } return ; } void pushup(int root,int l,int r) { if(ll[root<<1|1]!=rr[root<<1]) { sum[root]=sum[root<<1|1]+sum[root<<1]; } else sum[root]=sum[root<<1|1]+sum[root<<1]-1; ll[root]=ll[root<<1];rr[root]=rr[root<<1|1]; return ; } void build(int root,int l,int r) { if(l==r) { color[root]=a[l]; ll[root]=a[l]; rr[root]=a[l]; sum[root]=1; return ; } int mid=(l+r)/2; build(root<<1,l,mid); build(root<<1|1,mid+1,r); pushup(root,l,r); return ; } void push(int root,int l,int r) { //int mid=(l+r)>>1; lazy[root<<1]=lazy[root]; lazy[root<<1|1]=lazy[root]; sum[root<<1]=1; sum[root<<1|1]=1; ll[root<<1]=lazy[root]; rr[root<<1]=lazy[root]; rr[root<<1|1]=lazy[root]; ll[root<<1|1]=lazy[root]; color[root<<1]=lazy[root]; color[root<<1|1]=lazy[root]; lazy[root]=0; return ; } void update(int root,int left,int right,int l,int r,int v) { if(left>r||right<l)return ; if(left>=l&&right<=r) { lazy[root]=v; sum[root]=1; ll[root]=rr[root]=color[root]=v; return ; } if(lazy[root])push(root,left,right); int mid=(left+right)>>1; if(mid>=l)update(root<<1,left,mid,l,r,v); if(mid<r) update(root<<1|1,mid+1,right,l,r,v); pushup(root,left,right); return ; } int query(int root,int left,int right,int l,int r) { if(left>=l&&right<=r)return sum[root]; if(left>r||right<l)return 0; int mid=(left+right)>>1; if(lazy[root])push(root,left,right); int a=0,b=0; if(r<=mid)a=query(root<<1,left,mid,l,r); else if(mid<l) b=query(root<<1|1,mid+1,right,l,r); else { int res=query(root<<1,left,mid,l,r)+query(root<<1|1,mid+1,right,l,r); if(ll[root<<1|1]==rr[root<<1])res--; return res; } return a+b; } void change_cal(int x,int y,int v) { int fx=top[x],fy=top[y]; while(fx!=fy) { if(dep[fx]<dep[fy]){swap(fx,fy);swap(x,y);} update(1,1,n,l[fx],l[x],v); x=fa[fx];fx=top[x]; } if(l[x]>l[y])swap(x,y); update(1,1,n,l[x],l[y],v); } int query2(int root,int left,int right,int pos) { if(left>pos||right<pos)return 0; if(left==pos&&right==pos)return color[root]; int mid=(left+right)>>1; if(lazy[root])push(root,left,right); int a=0,b=0; if(pos<=mid)a=query2(root<<1,left,mid,pos); if(pos>mid)b=query2(root<<1|1,mid+1,right,pos); return a+b; } int find(int x) { return query2(1,1,n,l[x]); } int query_cal(int x,int y) { int ans=0; int fx=top[x],fy=top[y]; while(fx!=fy) { if(dep[fx]<dep[fy]){swap(fx,fy);swap(x,y);} ans+=query(1,1,n,l[fx],l[x]); if(find(fa[fx])==find(fx))ans--; x=fa[fx];fx=top[x]; } if(l[x]>l[y])swap(x,y); ans+=query(1,1,n,l[x],l[y]); return ans; } int main() { n=read();m=read(); for(int i=1;i<=n;i++) ch[i]=read(); for(int i=1;i<n;i++) { int x=read(),y=read(); add(x,y);add(y,x); } dep[1]=1;fa[1]=0; dfs1(1,1); // cout<<"qwq"<<endl; dfs2(1,1); // cout<<"QAQ"<<endl; build(1,1,n); for(int i=1;i<=m;i++) { char qwq;cin>>qwq; int x=read(),y=read(); if(qwq=='Q') { printf("%d\n",query_cal(x,y)); } else { int z=read(); change_cal(x,y,z); } } return 0; }