bzoj 2243 [SDOI2011]染色
2243: [SDOI2011]染色
Time Limit: 20 Sec Memory Limit: 512 MBSubmit: 8655 Solved: 3239
[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
Solution
树链剖分
线段树里面维护区间段数,区间左端点的颜色,区间右端点的颜色
询问的时候,合并两段要看它们连接的部分是否相同,我把那个左右搞反了,因为上面的点的编号小一点,所以上面是左
唔,最后一段要同时衔接左边段,和右边段,所以两边端点都要判断是否与最后一段相等
#include<algorithm> #include<iostream> #include<cstring> #include<cstdlib> #include<cstdio> #include<cmath> #include<queue> #define nn 100011 using namespace std; int dfn[nn],wo[nn],fir[nn],nxt[nn<<1],to[nn<<1],size[nn],top[nn],fa[nn],son[nn],dep[nn],color[nn],li,e; struct tree{ int l,r,numco,lco,rco,z; }t[nn<<2]; struct qu{ int num,lco,rco; }zc; int read() { int ans=0,f=1;char ch=getchar(); while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();} while(isdigit(ch)) {ans=ans*10+ch-'0';ch=getchar();} return ans*f; } void add(int u,int v) { nxt[++e]=fir[u];fir[u]=e;to[e]=v; /// nxt[++e]=fir[v];fir[v]=e;to[e]=u; } void dfs(int x) { size[x]=1; for(int i=fir[x];i;i=nxt[i]) if(to[i]!=fa[x]) { fa[to[i]]=x; dfs(to[i]); if(size[to[i]]>size[son[x]]) son[x]=to[i]; size[x]+=size[to[i]]; } } void dfs2(int x) { if(son[x]) { dep[son[x]]=dep[x]+1; dfn[++li]=son[x]; wo[son[x]]=li; top[son[x]]=top[x]; dfs2(son[x]); } for(int i=fir[x];i;i=nxt[i]) if(to[i]!=son[x]&&to[i]!=fa[x]) { dep[to[i]]=dep[x]+1; dfn[++li]=to[i]; wo[to[i]]=li; top[to[i]]=to[i]; dfs2(to[i]); } } void updata(int k) { t[k].lco=t[k<<1].lco; t[k].rco=t[k<<1|1].rco; t[k].numco=t[k<<1].rco==t[k<<1|1].lco? t[k<<1].numco+t[k<<1|1].numco-1:t[k<<1].numco+t[k<<1|1].numco; } void build(int k,int l,int r) { t[k].l=l;t[k].r=r; if(l==r) { t[k].numco=1; t[k].lco=color[dfn[l]]; t[k].rco=color[dfn[l]]; return; } int mid=(l+r)>>1; build(k<<1,l,mid); build(k<<1|1,mid+1,r); updata(k); } void pushdown(int k) { t[k<<1].lco=t[k].z;t[k<<1].rco=t[k].z;t[k<<1].numco=1;t[k<<1].z=t[k].z; t[k<<1|1].lco=t[k].z;t[k<<1|1].rco=t[k].z;t[k<<1|1].numco=1;t[k<<1|1].z=t[k].z; t[k].z=0; } void modify(int k,int l,int r,int c) { if(t[k].l==l&&t[k].r==r) { t[k].numco=1; t[k].lco=c; t[k].rco=c; t[k].z=c; return; } if(t[k].z) pushdown(k); int mid=(t[k].l+t[k].r)>>1; if(r<=mid) modify(k<<1,l,r,c); else if(l>mid) modify(k<<1|1,l,r,c); else { modify(k<<1,l,mid,c); modify(k<<1|1,mid+1,r,c); } updata(k); } qu query(int k,int l,int r) { if(t[k].l==l&&t[k].r==r) { qu o; o.lco=t[k].lco; o.rco=t[k].rco; o.num=t[k].numco; return o; } if(t[k].z) pushdown(k); int mid=(t[k].l+t[k].r)>>1; if(r<=mid) return query(k<<1,l,r); else if(l>mid) return query(k<<1|1,l,r); else { qu oo,oe; oo=query(k<<1,l,mid); oe=query(k<<1|1,mid+1,r); oo.num+=oe.num; if(oo.rco==oe.lco) oo.num--; oo.rco=oe.rco; return oo; } } void revise(int a,int b,int c) { while(top[a]!=top[b]) { if(dep[top[a]]<dep[top[b]]) swap(a,b); modify(1,wo[top[a]],wo[a],c); a=fa[top[a]]; } if(dep[a]>dep[b]) swap(a,b); modify(1,wo[a],wo[b],c); } int ask(int a,int b) { int res=0,prea=-1,preb=-1; while(top[a]!=top[b]) { if(dep[top[a]]>dep[top[b]]) { zc=query(1,wo[top[a]],wo[a]); res+=zc.num; if(prea>=0&&prea==zc.rco) res--; prea=zc.lco; ///反了 a=fa[top[a]]; } else { zc=query(1,wo[top[b]],wo[b]); res+=zc.num; if(preb>=0&&preb==zc.rco) res--; preb=zc.lco; b=fa[top[b]]; } } if(dep[a]<dep[b]) { zc=query(1,wo[a],wo[b]); res+=zc.num; if(prea>=0&&prea==zc.lco) res--; if(preb>=0&&preb==zc.rco) res--; } else { zc=query(1,wo[b],wo[a]); res+=zc.num; if(preb>=0&&preb==zc.lco) res--; if(prea>=0&&prea==zc.rco) res--; } return res; } int main() { char opt; int n,m,a,b,c,u,v; n=read();m=read(); for(int i=1;i<=n;i++) color[i]=read(); for(int i=1;i<n;i++) { u=read();v=read();add(u,v); } dfs(1); top[1]=1; dep[1]=1; dfn[++li]=1;wo[1]=li; dfs2(1); build(1,1,n); for(int i=1;i<=m;i++) { opt=getchar(); while(opt!='C'&&opt!='Q') opt=getchar(); a=read();b=read(); if(opt=='C') { c=read(); revise(a,b,c); } else printf("%d\n",ask(a,b)); } return 0; }