BZOJ 2243: [SDOI2011]染色 (树链剖分+线段树合并)
题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=2243
树链剖分的点剖分+线段树。漏了一个小地方,调了一下午...... 还是要细心啊!
结构体里lc表示这个区间的最左端的颜色,rc表示这个区间的最右端的颜色,sum表示这个区间的颜色段数目。回溯合并的时候要注意,左孩子的右端颜色要是等于右孩子左端颜色 sum就要-1。
代码如下:
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 using namespace std; 5 const int MAXN = 2e5 + 5; 6 struct data { 7 int next , to; 8 }edge[MAXN << 1]; 9 struct segtree { 10 int l , r , sum , lazy; //sum表示颜色段数量,lazy表示颜色延迟标记 11 int lc , rc; //lc表示区间的最左端颜色,rc表示最右端颜色 12 }T[MAXN << 2]; 13 int head[MAXN] , tot; 14 int son[MAXN] , size[MAXN] , par[MAXN] , dep[MAXN] , cnt; 15 int top[MAXN] , id[MAXN] , fid[MAXN]; 16 int a[MAXN]; 17 18 void init() { 19 memset(head , -1 , sizeof(head)); 20 tot = cnt = 0; 21 } 22 23 inline void add(int u , int v) { 24 edge[tot].next = head[u]; 25 edge[tot].to = v; 26 head[u] = tot++; 27 } 28 29 void dfs1(int u , int p , int d) { 30 dep[u] = d , size[u] = 1 , son[u] = u , par[u] = p; 31 for(int i = head[u] ; ~i ; i = edge[i].next) { 32 int v = edge[i].to; 33 if(v == p) 34 continue; 35 dfs1(v , u , d + 1); 36 if(size[v] >= size[son[u]]) 37 son[u] = v; 38 size[u] += size[v]; 39 } 40 } 41 42 void dfs2(int u , int p , int t) { 43 top[u] = t , id[u] = ++cnt; 44 fid[cnt] = u; 45 if(son[u] != u) 46 dfs2(son[u] , u , t); 47 for(int i = head[u] ; ~i ; i = edge[i].next) { 48 int v = edge[i].to; 49 if(v == p || v == son[u]) 50 continue; 51 dfs2(v , u , v); 52 } 53 } 54 55 void pushdown(int p) { 56 if(T[p].lazy != -1) { 57 int ls = p << 1 , rs = (p << 1)|1; 58 T[ls].rc = T[ls].lc = T[rs].lc = T[rs].rc = T[p].lazy; 59 T[ls].lazy = T[rs].lazy = T[p].lazy; 60 T[ls].sum = T[rs].sum = 1; //变成同一个颜色 sum就为1了 61 T[p].lazy = -1; 62 } 63 } 64 65 void pushup(int p) { 66 T[p].lc = T[p << 1].lc , T[p].rc = T[(p << 1)|1].rc; //这里注意要回溯上来,父节点的左右端颜色要更新 67 T[p].sum = T[p << 1].sum + T[(p << 1)|1].sum - (T[p << 1].rc == T[(p << 1)|1].lc); //合并操作:要是左孩子的最右端颜色等于右孩子最左端颜色,那就需要-1 68 } 69 70 void build(int p , int l , int r) { 71 int mid = (l + r) >> 1; 72 T[p].r = r , T[p].l = l , T[p].lc = a[fid[l]] , T[p].rc = a[fid[r]] , T[p].lazy = -1; 73 if(l == r) { 74 T[p].sum = 1; 75 return ; 76 } 77 build(p << 1 , l , mid); 78 build((p << 1)|1 , mid + 1 , r); 79 pushup(p); 80 } 81 82 void update(int p , int l , int r , int color) { 83 int mid = (T[p].l + T[p].r) >> 1; 84 if(T[p].l == l && T[p].r == r) { 85 T[p].sum = 1 , T[p].lazy = T[p].rc = T[p].lc = color; 86 return ; 87 } 88 pushdown(p); 89 if(r <= mid) { 90 update(p << 1 , l , r , color); 91 } 92 else if(l > mid) { 93 update((p << 1)|1 , l , r , color); 94 } 95 else { 96 update(p << 1 , l , mid , color); 97 update((p << 1)|1 , mid + 1 , r , color); 98 } 99 pushup(p); 100 } 101 102 int query(int p , int l , int r) { 103 int mid = (T[p].l + T[p].r) >> 1; 104 if(T[p].l == l && T[p].r == r) { 105 return T[p].sum; 106 } 107 pushdown(p); 108 if(r <= mid) { 109 return query(p << 1 , l , r); 110 } 111 else if(l > mid) { 112 return query((p << 1)|1 , l , r); 113 } 114 else { 115 return query(p << 1 , l , mid) + query((p << 1)|1 , mid + 1 , r) - (T[p << 1].rc == T[(p << 1)|1].lc); 116 } 117 } 118 119 int query_pos_color(int p , int pos) { 120 int mid = (T[p].l + T[p].r) >> 1; 121 if(T[p].l == T[p].r && pos == T[p].r) { 122 return T[p].lc; 123 } 124 pushdown(p); 125 if(pos <= mid) { 126 query_pos_color(p << 1 , pos); 127 } 128 else { 129 query_pos_color((p << 1)|1 , pos); 130 } 131 } 132 133 void find_update(int u , int v , int val) { 134 int fu = top[u] , fv = top[v]; 135 while(fu != fv) { 136 if(dep[fu] >= dep[fv]) { 137 update(1 , id[fu] , id[u] , val); 138 u = par[fu]; 139 fu = top[u]; 140 } 141 else { 142 update(1 , id[fv] , id[v] , val); 143 v = par[fv]; 144 fv = top[v]; 145 } 146 } 147 if(dep[u] > dep[v]) 148 update(1 , id[v] , id[u] , val); 149 else 150 update(1 , id[u] , id[v] , val); 151 } 152 153 int find_ans(int u , int v) { 154 int fu = top[u] , fv = top[v] , res = 0; 155 while(fu != fv) { 156 if(dep[fu] >= dep[fv]) { 157 res += query(1 , id[fu] , id[u]); 158 if(query_pos_color(1 , id[fu]) == query_pos_color(1 , id[par[fu]])) //要是fu节点和其父节点颜色相同就-1 159 res--; 160 u = par[fu]; 161 fu = top[u]; 162 } 163 else { 164 res += query(1 , id[fv] , id[v]); 165 if(query_pos_color(1 , id[fv]) == query_pos_color(1 , id[par[fv]])) //上同 166 res--; 167 v = par[fv]; 168 fv = top[v]; 169 } 170 } 171 if(dep[u] > dep[v]) { 172 res += query(1 , id[v] , id[u]); 173 return res; 174 } 175 else { 176 res += query(1 , id[u] , id[v]); 177 return res; 178 } 179 } 180 181 int main() 182 { 183 int n , m , u , v , val; 184 char q[5]; 185 while(~scanf("%d %d" , &n , &m)) { 186 init(); 187 for(int i = 1 ; i <= n ; ++i) 188 scanf("%d" , a + i); 189 for(int i = 1 ; i < n ; ++i) { 190 scanf("%d %d" , &u , &v); 191 add(u , v); 192 add(v , u); 193 } 194 dfs1(1 , 1 , 0); 195 dfs2(1 , 1 , 1); 196 build(1 , 1 , cnt); 197 while(m--) { 198 scanf("%s" , q); 199 if(q[0] == 'Q') { 200 scanf("%d %d" , &u , &v); 201 printf("%d\n" , find_ans(u , v)); 202 } 203 else { 204 scanf("%d %d %d" , &u , &v , &val); 205 find_update(u , v , val); 206 } 207 } 208 } 209 return 0; 210 }