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]之间。
Source
正解:树链剖分+线段树
解题报告:
链剖裸题,套个线段树。
这题唯一难的就在于查询颜色段的时候要考虑跨越查询区间时,要记得去掉重复的部分。合并区间的时候看一下两边区间相接的部分是否是相同颜色,相同的话减掉就可以了。
线段树维护这一段区间的左端点颜色,右端点颜色,区间不同颜色的和,记得lazy标记。
这题AC之前WA了两发,第一发是因为没考虑颜色可以为0,第二发是因为没有对于线段树跨越区间情况去重。
1 //It is made by jump~ 2 #include <iostream> 3 #include <cstdlib> 4 #include <cstring> 5 #include <cstdio> 6 #include <cmath> 7 #include <algorithm> 8 #include <ctime> 9 #include <vector> 10 #include <queue> 11 #include <map> 12 #include <set> 13 #ifdef WIN32 14 #define OT "%I64d" 15 #else 16 #define OT "%lld" 17 #endif 18 using namespace std; 19 typedef long long LL; 20 const int MAXN = 100011; 21 int n,m,ecnt,ans; 22 int first[MAXN],next[MAXN*2],to[MAXN*2],val[MAXN]; 23 int top[MAXN],size[MAXN],deep[MAXN],son[MAXN],id[MAXN],pre[MAXN],father[MAXN]; 24 char ch[12]; 25 int ql,qr; 26 27 struct node{ 28 int l,r,lazy; 29 int lc,rc;//左右端点的颜色 30 int sum; 31 }a[MAXN*4]; 32 33 inline int getint() 34 { 35 int w=0,q=0; 36 char c=getchar(); 37 while((c<'0' || c>'9') && c!='-') c=getchar(); 38 if (c=='-') q=1, c=getchar(); 39 while (c>='0' && c<='9') w=w*10+c-'0', c=getchar(); 40 return q ? -w : w; 41 } 42 43 inline void dfs1(int x,int fa){ 44 size[x]=1; 45 for(int i=first[x];i;i=next[i]) { 46 int v=to[i]; 47 if(v==fa)continue; 48 deep[v]=deep[x]+1; father[v]=x; 49 dfs1(v,x); 50 size[x]+=size[v];if(size[v]>size[son[x]]) son[x]=v; 51 } 52 } 53 54 inline void dfs2(int x,int fa){ 55 id[x]=++ecnt;pre[ecnt]=x; 56 if(son[x]) top[son[x]]=top[x],dfs2(son[x],x); 57 for(int i=first[x];i;i=next[i]) { 58 int v=to[i]; 59 if(v==fa || v==son[x]) continue; 60 top[v]=v; dfs2(v,x); 61 } 62 } 63 64 inline void build(int root,int l,int r){ 65 a[root].l=l; a[root].r=r; a[root].lazy=-1;//颜色可能为0!!! 66 if(l==r) { a[root].sum=1; a[root].lc=a[root].rc=val[pre[l]]; return ; } 67 int mid=(l+r)/2; int lc=root*2,rc=lc+1; 68 build(lc,l,mid); build(rc,mid+1,r); 69 a[root].sum=a[lc].sum+a[rc].sum; a[root].lc=a[lc].lc; a[root].rc=a[rc].rc; 70 if(!(a[lc].rc^a[rc].lc)) a[root].sum--; 71 } 72 73 inline int lca(int x,int y){ 74 int f1=top[x],f2=top[y]; 75 while(f1!=f2) { 76 if(deep[f1]<deep[f2]) swap(f1,f2),swap(x,y); 77 x=father[f1]; f1=top[x]; 78 } 79 if(deep[x]<deep[y]) swap(x,y); 80 return y; 81 } 82 83 inline void pushdown(int root){ 84 int lin=a[root].lazy; a[root].lazy=-1; 85 if(lin==-1 || a[root].l==a[root].r) return ; 86 int lc=root*2,rc=lc+1; 87 a[lc].lazy=a[rc].lazy=lin; 88 a[root].lc=a[root].rc=a[lc].lc=a[lc].rc=a[rc].lc=a[rc].rc=lin; 89 a[root].sum=a[lc].sum=a[rc].sum=1; 90 } 91 92 inline void update(int root){ 93 int lc=root*2,rc=lc+1; 94 a[root].sum=a[lc].sum+a[rc].sum; 95 if(!(a[lc].rc^a[rc].lc)) a[root].sum--; 96 a[root].lc=a[lc].lc; a[root].rc=a[rc].rc; 97 } 98 99 inline void query(int root,int l,int r){ 100 if(ql>qr) return ; 101 pushdown(root); 102 if(ql<=l && r<=qr) { 103 ans+=a[root].sum; 104 return ; 105 } 106 int mid=(l+r)/2; int lc=root*2,rc=lc+1; 107 if(qr<=mid) query(lc,l,mid); 108 else if(ql>mid) query(rc,mid+1,r); 109 else{//注意这里也合并一下左右!!!有可能两个端点相等 110 query(lc,l,mid); query(rc,mid+1,r); 111 if(a[lc].rc==a[rc].lc) ans--; 112 } 113 } 114 115 inline void change(int root,int l,int r,int z){ 116 if(ql>qr) return ; 117 pushdown(root); 118 if(ql<=l && r<=qr) { 119 a[root].lazy=z; a[root].lc=a[root].rc=a[root].lazy; a[root].sum=1; return ; 120 } 121 int mid=(l+r)/2; int lc=root*2,rc=lc+1; 122 if(ql<=mid) change(lc,l,mid,z); if(qr>mid) change(rc,mid+1,r,z); 123 update(root); 124 } 125 126 inline int getcol(int root,int x){ 127 pushdown(root); 128 if(a[root].l==a[root].r) return a[root].lc; 129 int mid=(a[root].l+a[root].r)/2; int lc=root*2,rc=lc+1; 130 if(x<=mid) return getcol(lc,x); else return getcol(rc,x); 131 } 132 133 inline void ask_change(int x,int f,int z){ 134 while(top[x]!=top[f]) { 135 ql=id[top[x]]; qr=id[x]; 136 change(1,1,n,z); 137 x=father[top[x]]; 138 } 139 ql=id[f],qr=id[x],change(1,1,n,z); 140 } 141 142 inline void ask_sum(int x,int f){ 143 while(top[x]!=top[f]) { 144 ql=id[top[x]]; qr=id[x]; 145 query(1,1,n); 146 if(getcol(1,id[top[x]])==getcol(1,id[father[top[x]]])) ans--;//判断相接的部分是否相同,跨越轻边的时候统计一下 147 x=father[top[x]]; 148 } 149 ql=id[f],qr=id[x],query(1,1,n); 150 } 151 152 inline void work(){ 153 n=getint(); m=getint(); 154 for(int i=1;i<=n;i++) val[i]=getint(); 155 int x,y; 156 for(int i=1;i<n;i++) { 157 x=getint(); y=getint(); 158 next[++ecnt]=first[x]; first[x]=ecnt; to[ecnt]=y; 159 next[++ecnt]=first[y]; first[y]=ecnt; to[ecnt]=x; 160 } 161 deep[1]=1; dfs1(1,0); ecnt=0; top[1]=1; dfs2(1,0); 162 build(1,1,n); int z,grand; 163 while(m--) { 164 scanf("%s",ch); 165 if(ch[0]=='Q') { 166 x=getint(); y=getint(); 167 grand=lca(x,y); ans=0; 168 ask_sum(x,grand); ask_sum(y,grand); 169 printf("%d\n",ans-1);//不管是连续还是不同颜色都是减一即可 170 } 171 else{ 172 x=getint(); y=getint(); z=getint(); 173 grand=lca(x,y); 174 ask_change(x,grand,z); ask_change(y,grand,z); 175 } 176 } 177 } 178 179 int main() 180 { 181 work(); 182 return 0; 183 }
本文作者:ljh2000
作者博客:http://www.cnblogs.com/ljh2000-jump/
转载请注明出处,侵权必究,保留最终解释权!