1. 程式人生 > >BZOJ2243: [SDOI2011]染色(樹鏈剖分/LCT)

BZOJ2243: [SDOI2011]染色(樹鏈剖分/LCT)

algo push 正整數 代碼 ESS += 樹鏈剖分 ask 一行

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

Sample Output

3
1
2

解題思路:

1.樹鏈剖分:

只修改鏈,不修改關系,樹鏈剖分。

線段樹維護樹鏈剖分序。

時間復雜度O(nlogn2)

代碼:

  1 #include<cstdio>
  2 #include<cstring>
  3 #include<algorithm>
  4
#define lll spc<<1 5 #define rrr spc<<1|1 6 using std::min; 7 using std::max; 8 using std::swap; 9 struct trnt{ 10 int lc; 11 int rc; 12 int lzt; 13 int val; 14 }tr[1000000]; 15 struct pnt{ 16 int hd; 17 int col; 18 int mxs; 19 int
ind; 20 int fa; 21 int tp; 22 int wgt; 23 int dp; 24 }p[1000000]; 25 struct ent{ 26 int twd; 27 int lst; 28 }e[1000000]; 29 struct bag{ 30 int cl; 31 int cr; 32 int vl; 33 bag friend operator + (bag a,bag b) 34 { 35 if(!a.cl) 36 a.cl=b.cl; 37 if(!b.cr) 38 b.cr=a.cr; 39 return (bag){a.cl,b.cr,(a.vl+b.vl-(a.cr==b.cl)<0)?0:(a.vl+b.vl-(a.cr==b.cl))}; 40 } 41 }; 42 int n,m; 43 int cnt; 44 int dfn; 45 char cmd[10]; 46 void ade(int f,int t) 47 { 48 cnt++; 49 e[cnt].twd=t; 50 e[cnt].lst=p[f].hd; 51 p[f].hd=cnt; 52 return ; 53 } 54 void pushup(int spc) 55 { 56 tr[spc].lc=tr[lll].lc; 57 tr[spc].rc=tr[rrr].rc; 58 tr[spc].val=tr[lll].val+tr[rrr].val-(tr[lll].rc==tr[rrr].lc); 59 return ; 60 } 61 void chg(int spc,int v) 62 { 63 tr[spc].val=1; 64 tr[spc].lc=tr[spc].rc=v; 65 tr[spc].lzt=v; 66 return ; 67 } 68 void pushdown(int spc) 69 { 70 if(tr[spc].lzt) 71 { 72 chg(lll,tr[spc].lzt); 73 chg(rrr,tr[spc].lzt); 74 tr[spc].lzt=0; 75 } 76 return ; 77 } 78 void build(int l,int r,int pos,int spc,int v) 79 { 80 if(l==r) 81 { 82 tr[spc].lc=tr[spc].rc=v; 83 tr[spc].val=1; 84 tr[spc].lzt=0; 85 return ; 86 } 87 int mid=(l+r)>>1; 88 if(pos<=mid) 89 build(l,mid,pos,lll,v); 90 else 91 build(mid+1,r,pos,rrr,v); 92 pushup(spc); 93 return ; 94 } 95 void Basic_dfs(int x,int f) 96 { 97 p[x].dp=p[f].dp+1; 98 p[x].fa=f; 99 int maxs=-1; 100 p[x].wgt=1; 101 for(int i=p[x].hd;i;i=e[i].lst) 102 { 103 int to=e[i].twd; 104 if(to==f) 105 continue; 106 Basic_dfs(to,x); 107 p[x].wgt+=p[to].wgt; 108 if(p[to].wgt>maxs) 109 { 110 maxs=p[to].wgt; 111 p[x].mxs=to; 112 } 113 } 114 return ; 115 } 116 void Build_dfs(int x,int tpl) 117 { 118 if(!x) 119 return ; 120 p[x].tp=tpl; 121 p[x].ind=++dfn; 122 build(1,n,dfn,1,p[x].col); 123 Build_dfs(p[x].mxs,tpl); 124 for(int i=p[x].hd;i;i=e[i].lst) 125 { 126 int to=e[i].twd; 127 if(p[to].ind) 128 continue; 129 Build_dfs(to,to); 130 } 131 } 132 void update(int l,int r,int ll,int rr,int spc,int v) 133 { 134 if(ll>rr) 135 return ; 136 if(l>rr||ll>r) 137 return ; 138 pushdown(spc); 139 if(ll<=l&&r<=rr) 140 { 141 chg(spc,v); 142 return ; 143 } 144 int mid=(l+r)>>1; 145 update(l,mid,ll,rr,lll,v); 146 update(mid+1,r,ll,rr,rrr,v); 147 pushup(spc); 148 return ; 149 } 150 bag mk(int a,int b,int c) 151 { 152 return (bag){a,b,c}; 153 } 154 bag ask(int l,int r,int ll,int rr,int spc) 155 { 156 if(l>rr||ll>r) 157 return mk(0,0,0); 158 pushdown(spc); 159 if(ll<=l&&r<=rr) 160 return mk(tr[spc].lc,tr[spc].rc,tr[spc].val); 161 int mid=(l+r)>>1; 162 return ask(l,mid,ll,rr,lll)+ask(mid+1,r,ll,rr,rrr); 163 } 164 int lca(int x,int y) 165 { 166 while(p[x].tp!=p[y].tp) 167 { 168 if(p[p[x].tp].dp<p[p[y].tp].dp) 169 swap(x,y); 170 x=p[p[x].tp].fa; 171 } 172 if(p[x].dp>p[y].dp) 173 swap(x,y); 174 return x; 175 } 176 void rvs(bag &a) 177 { 178 swap(a.cl,a.cr); 179 return ; 180 } 181 int main() 182 { 183 scanf("%d%d",&n,&m); 184 for(int i=1;i<=n;i++) 185 scanf("%d",&p[i].col); 186 for(int i=1;i<n;i++) 187 { 188 int a,b; 189 scanf("%d%d",&a,&b); 190 ade(a,b); 191 ade(b,a); 192 } 193 Basic_dfs(1,0); 194 Build_dfs(1,1); 195 while(m--) 196 { 197 scanf("%s",cmd); 198 if(cmd[0]==C) 199 { 200 int a,b,c; 201 scanf("%d%d%d",&a,&b,&c); 202 int f=lca(a,b); 203 while(p[a].tp!=p[f].tp) 204 { 205 update(1,dfn,p[p[a].tp].ind,p[a].ind,1,c); 206 a=p[p[a].tp].fa; 207 } 208 update(1,dfn,p[f].ind,p[a].ind,1,c); 209 a=b; 210 while(p[a].tp!=p[f].tp) 211 { 212 update(1,dfn,p[p[a].tp].ind,p[a].ind,1,c); 213 a=p[p[a].tp].fa; 214 } 215 update(1,dfn,p[f].ind,p[a].ind,1,c); 216 } 217 if(cmd[0]==Q) 218 { 219 int a,b; 220 221 scanf("%d%d",&a,&b); 222 int f=lca(a,b); 223 bag ans=(bag){0,0,0}; 224 while(p[a].tp!=p[f].tp) 225 { 226 ans=ask(1,dfn,p[p[a].tp].ind,p[a].ind,1)+ans; 227 a=p[p[a].tp].fa; 228 } 229 if(a!=f) 230 ans=ask(1,dfn,p[f].ind+1,p[a].ind,1)+ans; 231 bag ams=(bag){0,0,0}; 232 a=b; 233 while(p[a].tp!=p[f].tp) 234 { 235 ams=ask(1,dfn,p[p[a].tp].ind,p[a].ind,1)+ams; 236 a=p[p[a].tp].fa; 237 } 238 if(a!=f) 239 ams=ask(1,dfn,p[f].ind+1,p[a].ind,1)+ams; 240 ans=ask(1,dfn,p[f].ind,p[f].ind,1)+ans; 241 rvs(ans); 242 ans=ans+ams; 243 printf("%d\n",ans.vl); 244 } 245 } 246 return 0; 247 }

2.LCT:

比較板子了。

每次維護左側顏色和右側顏色(註意特判0節點值)

反轉時要反轉左右顏色。

路徑提取一下輸出答案就好了。

時間復雜度O(nlogn)理論上比樹剖快

但是:

蒟蒻的我:splay常數居然比logn大

技術分享圖片

代碼:

  1 #include<cstdio>
  2 #include<cstring>
  3 #include<algorithm>
  4 #define lll tr[spc].ch[0]
  5 #define rrr tr[spc].ch[1]
  6 #define ls ch[0]
  7 #define rs ch[1]
  8 using std::swap;
  9 struct trnt{
 10     int ch[2];
 11     int fa;
 12     int lzt;
 13     int chg;
 14     int sum;
 15     int val;
 16     int lc;
 17     int rc;
 18     int wgt;
 19     bool anc;
 20 }tr[1000000];
 21 int n,m;
 22 char cmd[10];
 23 bool whc(int spc)
 24 {
 25     return tr[tr[spc].fa].rs==spc;
 26 }
 27 void pushup(int spc)
 28 {
 29     tr[spc].wgt=tr[lll].wgt+tr[rrr].wgt+1;
 30     tr[spc].sum=tr[lll].sum+tr[rrr].sum+1-(tr[lll].rc==tr[spc].val)-(tr[rrr].lc==tr[spc].val);
 31     tr[spc].lc=tr[lll].lc?tr[lll].lc:tr[spc].val;
 32     tr[spc].rc=tr[rrr].rc?tr[rrr].rc:tr[spc].val;
 33     return ;
 34 }
 35 void trr(int spc)
 36 {
 37     if(!spc)
 38         return ;
 39     swap(lll,rrr);
 40     swap(tr[spc].lc,tr[spc].rc);
 41     tr[spc].lzt^=1;
 42     return ;
 43 }
 44 void upd(int spc,int v)
 45 {
 46     if(!spc)
 47         return ;
 48     tr[spc].val=tr[spc].lc=tr[spc].rc=v;
 49     tr[spc].sum=1;
 50     tr[spc].chg=v;
 51     return ;
 52 }
 53 void pushdown(int spc)
 54 {
 55     if(tr[spc].lzt)
 56     {
 57         trr(lll);
 58         trr(rrr);
 59         tr[spc].lzt=0;
 60     }
 61     if(tr[spc].chg)
 62     {
 63         upd(lll,tr[spc].chg);
 64         upd(rrr,tr[spc].chg);
 65         tr[spc].chg=0;
 66     }
 67     return ;
 68 }
 69 void recal(int spc)
 70 {
 71     if(!tr[spc].anc)
 72         recal(tr[spc].fa);
 73     pushdown(spc);
 74     return ;
 75 }
 76 void rotate(int spc)
 77 {
 78     int f=tr[spc].fa;
 79     bool k=whc(spc);
 80     tr[f].ch[k]=tr[spc].ch[!k];
 81     tr[spc].ch[!k]=f;
 82     if(tr[f].anc)
 83     {
 84         tr[spc].anc=1;
 85         tr[f].anc=0;
 86     }else
 87         tr[tr[f].fa].ch[whc(f)]=spc;
 88     tr[spc].fa=tr[f].fa;
 89     tr[f].fa=spc;
 90     tr[tr[f].ch[k]].fa=f;
 91     pushup(f);
 92     pushup(spc);
 93     return ;
 94 }
 95 void splay(int spc)
 96 {
 97     recal(spc);
 98     while(!tr[spc].anc)
 99     {
100         int f=tr[spc].fa;
101         if(tr[f].anc)
102         {
103             rotate(spc);
104             return ;
105         }
106         if(whc(spc)^whc(f))
107             rotate(spc);
108         else
109             rotate(f);
110         rotate(spc);
111     }
112     return ;
113 }
114 void access(int spc)
115 {
116     int lst=0;
117     while(spc)
118     {
119         splay(spc);
120         tr[rrr].anc=1;
121         tr[lst].anc=0;
122         rrr=lst;
123         pushup(spc);
124         lst=spc;
125         spc=tr[spc].fa;
126     }
127     return ;
128 }
129 void Mtr(int spc)
130 {
131     access(spc);
132     splay(spc);
133     trr(spc);
134     return ;
135 }
136 void split(int x,int y)
137 {
138     Mtr(x);
139     access(y);
140     splay(y);
141     return ;
142 }
143 void link(int x,int y)
144 {
145     Mtr(x);
146     tr[x].fa=y;
147     return;
148 }
149 int main()
150 {
151     scanf("%d%d",&n,&m);
152     for(int i=1;i<=n;i++)
153     {
154         tr[i].anc=1;
155         scanf("%d",&tr[i].val);
156         tr[i].lc=tr[i].rc=tr[i].val;
157     }
158     for(int i=1;i<n;i++)
159     {
160         int a,b;
161         scanf("%d%d",&a,&b);
162         link(a,b);
163     }
164     while(m--)
165     {
166         scanf("%s",cmd);
167         if(cmd[0]==Q)
168         {
169             int a,b;
170             scanf("%d%d",&a,&b);
171             split(a,b);
172             printf("%d\n",tr[b].sum);
173         }else{
174             int a,b,c;
175             scanf("%d%d%d",&a,&b,&c);
176             split(a,b);
177             upd(b,c);
178         }
179     }
180     return 0;
181 }

BZOJ2243: [SDOI2011]染色(樹鏈剖分/LCT)