bzoj 3123[Sdoi2013]森林 - 树上主席树 + 启发式合并
3123: [Sdoi2013]森林
Time Limit: 20 Sec Memory Limit: 512 MBDescription
Input
第一行包含一个正整数testcase,表示当前测试数据的测试点编号。保证1≤testcase≤20。
第二行包含三个整数N,M,T,分别表示节点数、初始边数、操作数。第三行包含N个非负整数表示 N个节点上的权值。
接下来 M行,每行包含两个整数x和 y,表示初始的时候,点x和点y 之间有一条无向边, 接下来 T行,每行描述一个操作,格式为“Q x y k”或者“L x y ”,其含义见题目描述部分。
Output
对于每一个第一类操作,输出一个非负整数表示答案。
Sample Input
1
8 4 8
1 1 2 2 3 3 4 4
4 7
1 8
2 4
2 1
Q 8 7 3 Q 3 5 1
Q 10 0 0
L 5 4
L 3 2 L 0 7
Q 9 2 5 Q 6 1 6
8 4 8
1 1 2 2 3 3 4 4
4 7
1 8
2 4
2 1
Q 8 7 3 Q 3 5 1
Q 10 0 0
L 5 4
L 3 2 L 0 7
Q 9 2 5 Q 6 1 6
Sample Output
2
2
1
4
2
2
1
4
2
HINT
对于第一个操作 Q 8 7 3,此时 lastans=0,所以真实操作为Q 8^0 7^0 3^0,也即Q 8 7 3。点8到点7的路径上一共有5个点,其权值为4 1 1 2 4。这些权值中,第三小的为 2,输出 2,lastans变为2。对于第二个操作 Q 3 5 1 ,此时lastans=2,所以真实操作为Q 3^2 5^2 1^2 ,也即Q 1 7 3。点1到点7的路径上一共有4个点,其权值为 1 1 2 4 。这些权值中,第三小的为2,输出2,lastans变为 2。之后的操作类似。
一道树上主席树的练习题
查询x-y的链的大小时,我们的思路都是二分权值,但此时是以每一个树的节点为根,因此x-y这条链上的信息就等于
root[x] + root[y] - root[lca(x, y)] - root[fa(lca(x, y))]
每一个节点的线段树都对应的是点到根的路径信息
合并就是启发式合并的操作,暴力加点
1 #include <iostream> 2 #include <cstring> 3 #include <cstdio> 4 #include <algorithm> 5 #include <cmath> 6 #define LL long long 7 #define lc seg[x].ch[0] 8 #define rc seg[x].ch[1] 9 10 using namespace std; 11 12 13 const int MAXN = 8e4 + 10, MAXM = 8e4 + 10; 14 int N, M, T; 15 int SIZE = 0; 16 LL ans; 17 LL lastans = 0; 18 int sum; 19 int size[MAXN]; 20 int cnt = 0; 21 int tot = 0; 22 int root[MAXN]; 23 int deep[MAXN]; 24 int ra[MAXN]; 25 int val[MAXN]; 26 int head[MAXN]; 27 int testcase; 28 int fa[30][MAXN]; 29 int father[MAXN]; 30 char opr[10]; 31 32 struct node { 33 int val; 34 int id; 35 } n[MAXN]; 36 37 inline LL read() 38 { 39 LL x = 0, w = 1; char ch = 0; 40 while(ch < '0' || ch > '9') { 41 if(ch == '-') { 42 w = -1; 43 } 44 ch = getchar(); 45 } 46 while(ch >= '0' && ch <= '9') { 47 x = x * 10 + ch - '0'; 48 ch = getchar(); 49 } 50 return x * w; 51 } 52 53 struct segment { 54 int ch[2]; 55 int num; 56 } seg[MAXN * 200]; 57 58 int find(int x) 59 { 60 if(x != father[x]) { 61 x = find(father[x]); 62 } 63 return father[x]; 64 } 65 66 void pushup(int x) 67 { 68 seg[x].num = seg[lc].num + seg[rc].num; 69 } 70 71 struct edge { 72 int v; 73 int next; 74 } g[MAXN * 10]; 75 76 void addedge(int u, int v) 77 { 78 g[++cnt].v = v; 79 g[cnt].next = head[u]; 80 head[u] = cnt; 81 } 82 83 void init() 84 { 85 for(int i = 1; i < MAXN; i++) { 86 father[i] = i; 87 } 88 } 89 90 void multify() 91 { 92 for(int j = 1; j < 20; j++) { 93 for(int i = 1; i <= N; i++) { 94 fa[j][i] = fa[j - 1][fa[j - 1][i]]; 95 } 96 } 97 } 98 99 void insert(int l, int r, int &x, int k) 100 { 101 seg[++tot] = seg[x]; 102 x = tot; 103 if(l == r) { 104 seg[x].num++; 105 return; 106 } 107 int mid = (l + r) >> 1; 108 if(k > mid) { 109 insert(mid + 1, r, rc, k); 110 } else { 111 insert(l, mid, lc, k); 112 } 113 pushup(x); 114 } 115 116 void build(int x, int top) 117 { 118 sum++; 119 father[x] = top; 120 deep[x] = deep[fa[0][x]] + 1; 121 root[x] = root[fa[0][x]]; 122 insert(1, SIZE, root[x], ra[x]); 123 for(int j = head[x]; j; j = g[j].next) { 124 int to = g[j].v; 125 if(fa[0][to] == 0 && to != top) { 126 fa[0][to] = x; 127 build(to, top); 128 } 129 } 130 } 131 132 void merge(int x, int f) 133 { 134 fa[0][x] = f; 135 deep[x] = deep[fa[0][x]] + 1; 136 for(int j = 1; j < 20; j++) { 137 fa[j][x] = fa[j - 1][fa[j - 1][x]]; 138 } 139 root[x] = root[fa[0][x]]; 140 insert(1, SIZE, root[x], ra[x]); 141 for(int j = head[x]; j; j = g[j].next) { 142 int to = g[j].v; 143 if(to != f) { 144 merge(to, x); 145 } 146 } 147 } 148 149 void print(int l, int r, int x) 150 { 151 cout<<l<<" "<<r<<" "<<seg[x].num<<endl; 152 if(l == r) { 153 return; 154 } 155 int mid = (l + r) >> 1; 156 print(l, mid, lc); 157 print(mid + 1, r, rc); 158 } 159 160 bool cmp(node a, node b) 161 { 162 return a.val < b.val; 163 } 164 165 int get_lca(int x, int y) 166 { 167 if(deep[x] < deep[y]) { 168 swap(x, y); 169 } 170 for(int j = 20; j >= 0; j--) { 171 if(deep[fa[j][x]] >= deep[y]) { 172 x = fa[j][x]; 173 } 174 } 175 if(x == y) { 176 return x; 177 } 178 for(int j = 20; j >= 0; j--) { 179 if(fa[j][x] != fa[j][y]) { 180 x = fa[j][x], y = fa[j][y]; 181 } 182 } 183 return fa[0][x]; 184 } 185 186 void query(int l, int r, int x, int y, int lca, int fca, int k) 187 { 188 if(l == r) { 189 ans = val[l]; 190 return; 191 } 192 int mid = (l + r) >> 1; 193 int NUM = seg[seg[x].ch[0]].num + seg[seg[y].ch[0]].num - seg[seg[lca].ch[0]].num - seg[seg[fca].ch[0]].num; 194 if(NUM >= k) { 195 query(l, mid, seg[x].ch[0], seg[y].ch[0], seg[lca].ch[0], seg[fca].ch[0], k); 196 } else { 197 query(mid + 1, r, seg[x].ch[1], seg[y].ch[1], seg[lca].ch[1], seg[fca].ch[1], k - NUM); 198 } 199 } 200 201 int main() 202 { 203 init(); 204 testcase = read(); 205 N = read(), M = read(), T = read(); 206 for(int i = 1; i <= N; i++) { 207 n[i].val = read(); 208 n[i].id = i; 209 } 210 sort(n + 1, n + 1 + N, cmp); 211 ra[n[1].id] = SIZE = 1; 212 val[1] = n[1].val; 213 for(int i = 2; i <= N; i++) { 214 if(n[i].val == n[i - 1].val) { 215 ra[n[i].id] = SIZE; 216 } else { 217 ra[n[i].id] = ++SIZE; 218 val[SIZE] = n[i].val; 219 } 220 } 221 for(int i = 1; i <= M; i++) { 222 int u = read(), v = read(); 223 addedge(u, v); 224 addedge(v, u); 225 } 226 for(int i = 1; i <= N; i++) { 227 sum = 0; 228 if(fa[0][i] == 0) 229 build(i, i); 230 size[i] = sum; 231 } 232 /*cout<<endl; 233 for(int i = 1; i <= N; i++) { 234 cout<<ra[i]<<" "<<val[i]<<endl; 235 }*/ 236 // return 0; 237 multify(); 238 /*cout<<endl; 239 for(int i = 1; i <= N; i++) { 240 cout<<fa[0][i]<<" "<<father[i]<<endl; 241 } 242 for(int i = 1; i <= N; i++) { 243 cout<<i<<endl; 244 print(1, SIZE, root[i]); 245 cout<<endl<<endl; 246 } 247 return 0;*/ 248 for(int i = 1; i <= T; i++) { 249 scanf("%s", opr); 250 if(opr[0] == 'Q') { 251 int x = read(), y = read(), k = read(); 252 x = x ^ lastans, y = y ^ lastans, k = k ^ lastans; 253 // cout<<x<<" "<<y<<" "<<k<<endl; 254 int lca = get_lca(x, y); 255 query(1, SIZE, root[x], root[y], root[lca], root[fa[0][lca]], k); 256 printf("%lld\n", ans); 257 lastans = ans; 258 } else { 259 int x = read(), y = read(); 260 x = x ^ lastans, y = y ^ lastans; 261 // cout<<x<<" "<<y<<endl; 262 int u = find(x), v = find(y); 263 // cout<<u<<" "<<v<<" "<<size[u]<<" "<<size[v]<<endl; 264 addedge(x, y); 265 addedge(y, x); 266 if(size[u] > size[v]) { 267 size[u] += size[v]; 268 father[v] = u; 269 merge(y, x); 270 } else { 271 size[v] += size[u]; 272 father[u] = v; 273 merge(x, y); 274 } 275 //cout<<i<<endl; 276 // print(1, SIZE, root[16]); 277 // cout<<endl<<endl; 278 // return 0; 279 } 280 } 281 } 282 283 /* 284 1 285 20 12 20 286 412060525 42425138 67114752 160822495 201962681 926214957 380263349 733667141 869039239 641017702 154667400 461702107 438851950 176272938 209229857 985208975 762952138 936593832 409183276 999506034 287 2 17 288 4 1 289 15 3 290 3 10 291 9 10 292 7 16 293 19 15 294 13 2 295 6 2 296 3 14 297 7 18 298 8 15 299 Q 6 17 2 300 Q 762952152 762952154 762952139 301 L 380263329 380263352 302 L 380263357 380263333 303 Q 380263356 380263359 380263348 304 L 641017709 641017703 305 L 641017716 641017700 306 Q 641017716 641017704 641017698 307 Q 380263359 380263357 380263345 308 L 733667140 733667136 309 L 733667150 733667156 310 L 733667145 733667142 311 Q 733667149 733667145 733667140 312 Q 67114772 67114761 67114759 313 Q 733667145 733667159 733667142 314 Q 380263359 380263356 380263351 315 Q 869039233 869039232 869039237 316 Q 380263359 380263345 380263356 317 Q 733667136 733667140 733667143 318 Q 412060537 412060516 412060519 319 */