bzoj 2243 树链剖分+线段树
题目描述
在一颗点数为N<100,000的树上,每个点有一个颜色。请你实现两种操作 1. 给一段路径u->v染色 2. 询问路径u->v上有多少种颜色吐槽:
1. 4KB的代码...
2. 唉.... 这题的思路非常好想... 但是我还是捉了好久....真弱...
3. 我尽量把代码写的清楚了...
3. 我尽量把代码写的清楚了...
算法分析:
1. 基于树的动态统计,还是要先做树链剖分
2. 至于线段怎么维护是个问题,这里我的方法是: 线段树记录每个区间的颜色段数,和最左段与最右段的颜色。更新的话要用到懒惰标记法。
3. 比维护/查询边要好写吧....
1 // figo 5.16.2012
2 // template & head file
3 #include<cassert>
4 #include<iostream>
5 #include<cstdio>
6 #include<cstring>
7 using namespace std;
8 template <typename T> inline void chkmin(T &a, const T b) { if(a > b) a = b;}
9 template <typename T> inline void chkmax(T &a, const T b) { if(a < b) a = b;}
10 // graph
11 const int V = 100005;
12 const int E = V * 2;
13 int head[V],pnt[E],nxt[E],color[V],e,n;
14 void add_edge( int u, int v){
15 nxt[e] = head[u];
16 head[u] = e;
17 pnt[e] = v;
18 e ++;
19 }
20 // segment tree
21 int LT,RT;
22 int lt[V<<2], rt[V<<2] ,clr[V<<2], cover[V<<2];
23 void pushdown( int pos, int L, int R){
24 if(L == R){ return;}
25 if(cover[pos] == 1) {
26 cover[pos]= 0;
27 clr[pos<<1] = clr[pos<<1|1] = 1;
28 lt[pos<<1] = rt[pos<<1] = lt[pos<<1|1] = rt[pos<<1|1] = lt[pos];
29 cover[pos<<1] = cover[pos<<1|1] = 1;
30 }
31 }
32 void upt( int pos, int L, int R){
33 if(L==R) return;
34 lt[pos] = lt[pos << 1];
35 rt[pos] = rt[pos << 1 | 1];
36 clr[pos] = clr[pos<<1] + clr[pos<<1|1] - (rt[pos<<1]==lt[pos<<1|1]);
37 }
38 int __ans,__last;
39 void update( int l, int r, int pos, int L, int R, char cmd, int c = 0){
40 if(L >= l && R <= r){
41 if(cmd == 'C'){
42 cover[pos] = clr[pos] = 1;
43 lt[pos] = rt[pos] = c;
44 }
45 if(L == l) LT = lt[pos];
46 if(R == r) RT = rt[pos];
47 __ans += clr[pos] - (__last==lt[pos]);
48 __last = rt[pos];
49 return;
50 }
51 pushdown(pos,L,R);
52 int mid = L + R >> 1;
53 if(mid >= l) update(l,r,pos << 1, L, mid,cmd, c);
54 if(mid < r) update(l,r,pos<<1|1, mid+1,R,cmd, c);
55 upt(pos,L,R);
56 }
57 // dsu
58 int parent[V];
59 int find( int u){
60 return u == parent[u] ? u : parent[u] = find(parent[u]);
61 }
62 // divide and conquer
63 const int inf = ~0u>>2;
64 int sz[V],P[V],heavy[V],deep[V],flag[V];
65 int dfs( int u, int f){
66 int mx = -1, s = -1;
67 sz[u] = 1;
68 for( int i = head[u];i!=-1; i = nxt[i]){
69 int v = pnt[i];
70 if(v == f) continue;
71 deep[v] = deep[u] + 1;
72 P[v] = u;
73 dfs(v,u);
74 sz[u] += sz[v];
75 if(sz[v] > mx){
76 mx = sz[v]; s = v;
77 }
78 }
79 heavy[u] = s;
80 if(s >= 0) parent[s] = u;
81 }
82 int prepare(){
83 for( int i =0; i<n; i++) parent[i] = i;
84 deep[0] = 0;P[0] = -1;
85 dfs(0,0);
86 int segsz = 0;
87 for( int i=0; i<n; i++) if(heavy[i] == -1){
88 int v = i;
89 while(v && heavy[P[v]] == v){
90 update(segsz,segsz,1,0,n,'C',color[v]);
91 flag[v] = segsz ++;
92 v = P[v];
93 }
94 update(segsz,segsz,1,0,n,'C',color[v]);
95 flag[v] = segsz ++;
96 }
97 assert(segsz==n);
98 }
99 // operator
100 int lca( int u, int v){
101 while(1){
102 int U = find(u);
103 int V = find(v);
104 if(U == V) return deep[u] < deep[v] ? u : v;
105 else if(deep[U] >= deep[V])
106 u = P[U];
107 else v = P[V];
108 }
109 }
110 int query( int u, int p, char cmd, int c=0){
111 int ans = 0;
112 int last = -1;
113 while(u != P[p]){
114 int l = flag[u];
115 int v = find(u);
116 if(deep[v]<deep[p]) v = p;
117 int r = flag[v];
118 __ans =0; __last = -1;
119 update(l,r,1,0,n,cmd,c);
120 ans += __ans - (LT == last);
121 last = RT;
122 u = P[v];
123 }
124 return ans;
125 }
126 // main
127 int ask( int u, int v, char cmd, int c=0){
128 int p = lca(u,v);
129 return query(u,p,cmd,c) + query(v,p,cmd,c) - 1;
130 }
131 int main(){
132 int m,u,v;
133 scanf("%d%d",&n,&m);
134 e = 0;
135 for( int i=0;i<n;i++) head[i] = -1;
136 for( int i=0;i<n;i++) scanf("%d",&color[i]);
137 for( int i=1;i<n;i++){
138 scanf("%d%d",&u,&v);
139 u--; v--;
140 add_edge(u,v);
141 add_edge(v,u);
142 }
143 prepare();
144 char cmd[2]; int c=0;
145 while(m--){
146 scanf("%s%d%d",cmd,&u,&v);
147 u--; v--;
148 if(cmd[0]=='C') scanf("%d",&c);
149 int ans = ask(u,v,cmd[0],c);
150 if(cmd[0]=='Q') printf("%d\n",ans);
151 }
152 }