bzoj 2243 [SDOI2011]染色(树链剖分+线段树合并)
【bzoj2243】[SDOI2011]染色
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]之间。、
题解:
题目很好理解,它不是边染色,而是点染色,这个性质是比较好的,边染色还需要裂点。
看的题目就可以想到这是树链剖分模板题吧,套个裸的线段树合并,其实没有什么合并的
东西,发现一段线段的不同颜色,那么就需要记录左端点和右端点颜色,如果左区间右端
点和右区间左端颜色一样,那么总颜色-1,这个比较好理解的吧,然后记录一个该区间总
颜色数,就可以统计了。
程序比较结构化
两个dfs预处理,lca,线段树,询问处理+更新处理,就ok了,代码比较清晰。
1 #include<cstring> 2 #include<cmath> 3 #include<iostream> 4 #include<algorithm> 5 #include<cstdio> 6 #include<cstdlib> 7 #define N 100007 8 using namespace std; 9 10 int n,m,sz=0; 11 int cnt,head[N],next[N*2],rea[N*2]; 12 int a[N]; 13 int fa[N][20],size[N],pos[N],bel[N],deep[N]; 14 char ch[2]; 15 struct Node 16 { 17 int lc,rc,tag,num; 18 }tr[N*5]; 19 20 void add(int u,int v){next[++cnt]=head[u],head[u]=cnt,rea[cnt]=v;} 21 void dfs_init(int u) 22 { 23 size[u]=1; 24 for (int i=1;(1<<i)<=deep[u];i++) 25 fa[u][i]=fa[fa[u][i-1]][i-1]; 26 for (int i=head[u];i!=-1;i=next[i]) 27 { 28 int v=rea[i]; 29 if (v==fa[u][0]) continue; 30 deep[v]=deep[u]+1; 31 fa[v][0]=u; 32 dfs_init(v); 33 size[u]+=size[v]; 34 } 35 } 36 void dfs_make(int u,int chain) 37 { 38 int k=0; 39 pos[u]=++sz,bel[u]=chain; 40 for (int i=head[u];i!=-1;i=next[i]) 41 { 42 int v=rea[i]; 43 if (deep[v]>deep[u]&&size[v]>size[k]) k=v; 44 } 45 if (k==0) return; 46 dfs_make(k,chain); 47 for (int i=head[u];i!=-1;i=next[i]) 48 { 49 int v=rea[i]; 50 if (deep[v]>deep[u]&&v!=k) dfs_make(v,v); 51 } 52 } 53 int lca(int a,int b) 54 { 55 if (deep[a]<deep[b]) swap(a,b); 56 int i; 57 for (i=0;(1<<i)<=deep[a];i++); 58 i--; 59 for (int j=i;j>=0;j--) 60 if (deep[a]-(1<<j)>=deep[b]) a=fa[a][j]; 61 if (a==b) return a; 62 for (int j=i;j>=0;j--) 63 if (fa[a][j]!=fa[b][j]) a=fa[a][j],b=fa[b][j]; 64 return fa[a][0]; 65 } 66 void updata_down(int l,int r,int p) 67 { 68 int tag=tr[p].tag;tr[p].tag=-1; 69 if (tag==-1||l==r) return; 70 tr[p<<1].num=tr[p<<1|1].num=1; 71 tr[p<<1].tag=tr[p<<1|1].tag=tag; 72 tr[p<<1].lc=tr[p<<1].rc=tag; 73 tr[p<<1|1].lc=tr[p<<1|1].rc=tag; 74 } 75 void updata_up(int l,int r,int p) 76 { 77 tr[p].lc=tr[p<<1].lc,tr[p].rc=tr[p<<1|1].rc; 78 tr[p].num=tr[p<<1].num+tr[p<<1|1].num; 79 if (tr[p<<1].rc==tr[p<<1|1].lc) tr[p].num--; 80 } 81 void change(int l,int r,int p,int x,int y,int z) 82 { 83 updata_down(l,r,p); 84 if (l==x&&y==r) 85 {tr[p].num=1,tr[p].lc=tr[p].rc=tr[p].tag=z;return;} 86 int mid=(l+r)>>1; 87 if (y<=mid) change(l,mid,p<<1,x,y,z); 88 else if (x>mid) change(mid+1,r,p<<1|1,x,y,z); 89 else change(l,mid,p<<1,x,mid,z),change(mid+1,r,p<<1|1,mid+1,y,z); 90 updata_up(l,r,p); 91 } 92 int query(int l,int r,int p,int x,int y) 93 { 94 updata_down(l,r,p); 95 if (l==x&&y==r) return tr[p].num; 96 int mid=(l+r)>>1,res; 97 if (y<=mid) res=query(l,mid,p<<1,x,y); 98 else if (x>mid) res=query(mid+1,r,p<<1|1,x,y); 99 else 100 { 101 res=query(l,mid,p<<1,x,mid)+query(mid+1,r,p<<1|1,mid+1,y); 102 if (tr[p<<1].rc==tr[p<<1|1].lc) res--; 103 } 104 return res; 105 } 106 int find(int l,int r,int p,int x) 107 { 108 updata_down(l,r,p); 109 if (l==r) return tr[p].lc; 110 int mid=(l+r)>>1; 111 if (x<=mid) return find(l,mid,p<<1,x); 112 else return find(mid+1,r,p<<1|1,x); 113 } 114 int solvequery(int x,int fq) 115 { 116 int res=0; 117 while(bel[x]!=bel[fq]) 118 { 119 res+=query(1,n,1,pos[bel[x]],pos[x]); 120 if (find(1,n,1,pos[bel[x]])==find(1,n,1,pos[fa[bel[x]][0]])) res--; 121 x=fa[bel[x]][0]; 122 } 123 res+=query(1,n,1,pos[fq],pos[x]); 124 return res; 125 } 126 void solvechange(int x,int fq,int z) 127 { 128 while(bel[x]!=bel[fq]) 129 { 130 change(1,n,1,pos[bel[x]],pos[x],z); 131 x=fa[bel[x]][0]; 132 } 133 change(1,n,1,pos[fq],pos[x],z); 134 } 135 int main() 136 { 137 memset(head,-1,sizeof(head));tr[1].tag=-1; 138 scanf("%d%d",&n,&m); 139 for(int i=1;i<=n;i++) 140 scanf("%d",&a[i]); 141 int x,y,z; 142 for (int i=1;i<n;i++) 143 { 144 scanf("%d%d",&x,&y); 145 add(x,y),add(y,x); 146 } 147 dfs_init(1); 148 dfs_make(1,1); 149 for (int i=1;i<=n;i++) 150 change(1,n,1,pos[i],pos[i],a[i]); 151 //============================================================== 152 for (int i=1;i<=m;i++) 153 { 154 scanf("%s",ch); 155 if (ch[0]=='Q') 156 { 157 scanf("%d%d",&x,&y); 158 int par=lca(x,y); 159 printf("%d\n",solvequery(x,par)+solvequery(y,par)-1); 160 } 161 else 162 { 163 scanf("%d%d%d",&x,&y,&z); 164 int par=lca(x,y); 165 solvechange(x,par,z),solvechange(y,par,z); 166 } 167 } 168 }