BZOJ 3123: [Sdoi2013]森林
3123: [Sdoi2013]森林
Time Limit: 20 Sec Memory Limit: 512 MBSubmit: 2745 Solved: 808
[Submit][Status][Discuss]
Description
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。之后的操作类似。
Source
首先,考虑一下如果没有加边操作,可以怎么做呢?主席树吧,每个点上挂一个版本,由树上父亲的版本修改而来,包含该点到根路径上所有点的权值信息。查询的时候只需要取出x,y上的答案,去掉lca(x,y),lca(x,y).father的答案即可得到x到y路径上的答案了。
因为有加边操作,每次需要重新DFS处理主席树,按秩合并的思想,保留原本大小大的一棵树不变,重新DFS小的一棵即可。
复杂度$O(Nlog^{2}N)$
1 #include <bits/stdc++.h> 2 const int siz = 200005, tre = 20000005; 3 int n, m, q, val[siz], map[siz], tot, hd[siz], to[siz], nt[siz], edge, root[siz], ls[tre], rs[tre], sm[tre], cnt, vis[siz], fa[siz][25], dep[siz], bl[siz], sz[siz], qa[siz], qb[siz], tail; 4 inline int find(int u) { return bl[u] == u ? u : bl[u] = find(bl[u]); } 5 inline void Union(int a, int b) { a = find(a), b = find(b); if (a ^ b)bl[a] = b, sz[b] += sz[a]; } 6 void insert(int &t, int f, int l, int r, int p) { 7 t = ++cnt; ls[t] = ls[f], rs[t] = rs[f], sm[t] = sm[f] + 1; 8 if (l != r) { int mid = (l + r) >> 1; (p <= mid ? insert(ls[t], ls[f], l, mid, p) : insert(rs[t], rs[f], mid + 1, r, p)); } 9 } 10 void dfs(int u, int f) { vis[u] = 1; 11 if (u && f)Union(u, f); 12 dep[u] = dep[f] + 1, fa[u][0] = f; 13 insert(root[u], root[f], 1, tot, val[u]); 14 for (int i = 1; i < 25; ++i)fa[u][i] = fa[fa[u][i - 1]][i - 1]; 15 for (int i = hd[u]; i; i = nt[i])if (to[i] != f)dfs(to[i], u); 16 } 17 inline int lca(int a, int b) { 18 if (dep[a] < dep[b])a ^= b ^= a ^= b; 19 for (int i = 24; ~i; --i)if (dep[fa[a][i]] >= dep[b])a = fa[a][i]; 20 for (int i = 24; ~i; --i)if (fa[a][i] ^ fa[b][i])a = fa[a][i], b = fa[b][i]; 21 return a == b ? a : fa[a][0]; 22 } 23 inline void add(int a, int b) { qa[tail] = root[a], qb[tail++] = b; } 24 int qry(int l, int r, int k) { if (l == r)return l; int s = 0, mid = (l + r) >> 1; 25 for (int i = 0; i < tail; ++i)s += qb[i] * sm[ls[qa[i]]]; 26 for (int i = 0; i < tail; ++i)qa[i] = s < k ? rs[qa[i]] : ls[qa[i]]; 27 return s < k ? qry(mid + 1, r, k - s) : qry(l, mid, k); 28 } 29 inline void adde(int x, int y) { 30 nt[++edge] = hd[x], to[edge] = y, hd[x] = edge, 31 nt[++edge] = hd[y], to[edge] = x, hd[y] = edge; 32 } 33 signed main(void) { 34 scanf("%*d%d%d%d", &n, &m, &q); 35 for (int i = 1; i <= n; ++i)scanf("%d", val + i), map[++tot] = val[i], sz[i] = 1, bl[i] = i; 36 std::sort(map + 1, map + tot + 1); tot = std::unique(map + 1, map + tot + 1) - map; 37 for (int i = 1; i <= n; ++i)val[i] = std::lower_bound(map + 1, map + tot, val[i]) - map; 38 for (int i = 1, x, y; i <= m; ++i)scanf("%d%d", &x, &y), adde(x, y); 39 for (int i = 1; i <= n; ++i)if (!vis[i])dfs(i, 0); 40 for (int i = 1, ans = 0, x, y, k, t; i <= q; ++i) { char c = getchar(); while (c != 'Q' && c != 'L')c = getchar(); 41 if (c == 'L') { scanf("%d%d", &x, &y), x ^= ans, y ^= ans, adde(x, y); if (sz[find(x)] > sz[find(y)])dfs(y, x); else dfs(x, y); } 42 else scanf("%d%d%d", &x, &y, &k), x ^= ans, y ^= ans, k ^= ans, tail = 0, 43 add(x, 1), add(y, 1), add(t = lca(x, y), -1), add(fa[t][0], -1), printf("%d\n", ans = map[qry(1, tot, k)]); 44 } 45 }
发现我代码写长了就有毒…… 300+代码无限RE中
1 #include <cstdio> 2 #include <cstring> 3 #include <iostream> 4 #include <algorithm> 5 6 inline char nextC(void) 7 { 8 static const int siz = 1024; 9 10 static char buf[siz]; 11 static char *hd = buf + siz; 12 static char *tl = buf + siz; 13 14 if (hd == tl) 15 fread(hd = buf, 1, siz, stdin); 16 17 return *hd++; 18 } 19 20 inline int nextI(void) 21 { 22 register int ret = 0; 23 register int neg = false; 24 register int bit = nextC(); 25 26 for (; bit < 48; bit = nextC()) 27 if (bit == '-')neg ^= true; 28 29 for (; bit > 47; bit = nextC()) 30 ret = ret * 10 + bit - 48; 31 32 return neg ? -ret : ret; 33 } 34 35 inline bool nextO(void) 36 { 37 register char c = nextC(); 38 39 while (c != 'Q' && c != 'L') 40 c = nextC(); 41 42 return c == 'Q'; 43 } 44 45 const int siz = 1000005; 46 47 int n, m, q; 48 49 int val[siz]; 50 int map[siz], tot; 51 52 inline void initMap(void) 53 { 54 tot = 0; 55 56 for (int i = 1; i <= n; ++i) 57 map[++tot] = val[i]; 58 59 // printf("tot = %d\n", tot); 60 // 61 // for (int i = 1; i < tot; ++i) 62 // printf("%d ", map[i]); 63 // puts(""); 64 65 using namespace std; 66 67 sort(map + 1, map + tot + 1); 68 69 tot = unique(map + 1, map + tot + 1) - map; 70 71 for (int i = 1; i <= n; ++i) 72 val[i] = lower_bound(map + 1, map + tot, val[i]) - map; 73 74 // printf("tot = %d\n", tot); 75 // 76 // for (int i = 1; i < tot; ++i) 77 // printf("%d ", map[i]); 78 // puts(""); 79 } 80 81 int edge; 82 int hd[siz]; 83 int nt[siz]; 84 int to[siz]; 85 86 inline void initEdge(void) 87 { 88 edge = 0; 89 memset(hd, -1, sizeof(hd)); 90 // static int sz = sizeof(int); 91 // memset(hd, -1, sz * (n + 5)); 92 } 93 94 95 inline void addEdge(int x, int y) 96 { 97 nt[edge] = hd[x]; to[edge] = y; hd[x] = edge++; 98 nt[edge] = hd[y]; to[edge] = x; hd[y] = edge++; 99 } 100 101 int cnt; 102 int root[siz]; 103 int ls[siz * 20]; 104 int rs[siz * 20]; 105 int sm[siz * 20]; 106 107 inline void initTree(void) 108 { 109 cnt = 0; 110 memset(root, 0, sizeof(root)); 111 // static int sz = sizeof(int); 112 // memset(root, 0, sz * (n + 5)); 113 } 114 115 void insert(int &t, int f, int l, int r, int p, int v) 116 { 117 t = ++cnt; 118 119 ls[t] = ls[f]; 120 rs[t] = rs[f]; 121 sm[t] = sm[f] + v; 122 123 // printf("%d %d %d %d\n", t, l, r, sm[t]); 124 125 if (l != r) 126 { 127 int mid = (l + r) >> 1; 128 129 if (p <= mid) 130 insert(ls[t], ls[f], l, mid, p, v); 131 else 132 insert(rs[t], rs[f], mid + 1, r, p, v); 133 } 134 } 135 136 int fa[siz][25], dep[siz]; 137 138 inline void initLCA(void) 139 { 140 memset(dep, 0, sizeof(dep)); 141 // static int sz = sizeof(int); 142 // memset(dep, 0, sz * (n + 5)); 143 } 144 145 inline int lca(int a, int b) 146 { 147 if (dep[a] < dep[b]) 148 a ^= b ^= a ^= b; 149 150 for (int i = 24; i >= 0; --i) 151 if (dep[fa[a][i]] >= dep[b]) 152 a = fa[a][i]; 153 154 if (a == b)return a; 155 156 for (int i = 24; i >= 0; --i) 157 if (fa[a][i] != fa[b][i]) 158 a = fa[a][i], 159 b = fa[b][i]; 160 161 return fa[a][0]; 162 } 163 164 int f[siz], g[siz]; 165 166 inline void initUnion(void) 167 { 168 for (int i = 0; i <= n; ++i) 169 f[i] = i, g[i] = 1; 170 } 171 172 inline int find(int u) 173 { 174 static int stk[siz], top = 0; 175 176 while (f[u] != u) 177 stk[++top] = u, u = f[u]; 178 179 while (top) 180 f[stk[top--]] = u; 181 182 return u; 183 } 184 185 inline void Union(int a, int b) 186 { 187 if (!a)return; 188 if (!b)return; 189 190 a = find(a); 191 b = find(b); 192 193 if (a != b) 194 { 195 g[b] += g[a]; 196 f[a] = b; 197 } 198 } 199 200 void dfs(int u, int fr) 201 { 202 // printf("debug: dfs %d %d\n", u, fr); 203 204 Union(u, fr); 205 206 fa[u][0] = fr; 207 208 dep[u] = dep[fr] + 1; 209 210 for (int i = 1; i < 25; ++i) 211 fa[u][i] = fa[fa[u][i - 1]][i - 1]; 212 213 insert(root[u], root[fr], 1, tot, val[u], 1); 214 215 for (int i = hd[u]; ~i; i = nt[i]) 216 if (to[i] != fr)dfs(to[i], u); 217 } 218 219 int queA[siz], queB[siz], tail; 220 221 inline void initQue(void) 222 { 223 tail = 0; 224 } 225 226 inline void addQue(int a, int b) 227 { 228 queA[tail] = root[a]; 229 queB[tail++] = b; 230 } 231 232 int query(int l, int r, int k) 233 { 234 if (l == r)return l; 235 236 int s = 0, mid = (l + r) >> 1; 237 238 for (int i = 0; i < tail; ++i) 239 s += sm[ls[queA[i]]] * queB[i]; 240 241 if (s >= k) 242 { 243 for (int i = 0; i < tail; ++i) 244 queA[i] = ls[queA[i]]; 245 246 return query(l, mid, k); 247 } 248 else 249 { 250 for (int i = 0; i < tail; ++i) 251 queA[i] = rs[queA[i]]; 252 253 return query(mid + 1, r, k - s); 254 } 255 } 256 257 int ans; 258 259 signed main(void) 260 { 261 for (int cas = nextI(); cas--; ) 262 { 263 n = nextI(); 264 m = nextI(); 265 q = nextI(); 266 267 for (int i = 1; i <= n; ++i) 268 val[i] = nextI(); 269 270 initMap(); 271 initEdge(); 272 initTree(); 273 initUnion(); 274 275 for (int i = 1; i <= m; ++i) 276 { 277 int x = nextI(); 278 int y = nextI(); 279 addEdge(x, y); 280 } 281 282 for (int i = 1; i <= n; ++i) 283 if (g[find(i)] == 1) 284 dfs(i, 0); 285 286 // puts("debug: prework finished"); 287 288 for (int i = 1; i <= q; ++i) 289 { 290 if (nextO()) // Query 291 { 292 int x = nextI() ^ ans; 293 int y = nextI() ^ ans; 294 int k = nextI() ^ ans; 295 296 int t = lca(x, y); 297 298 // printf("debug: lca %d %d = %d\n", x, y, t); 299 300 initQue(); 301 302 addQue(x, +1); 303 addQue(y, +1); 304 addQue(t, -1); 305 addQue(fa[t][0], -1); 306 307 // for (int i = 0; i < tail; ++i) 308 // printf("que %d %d\n", queA[i], queB[i]); 309 310 printf("%d\n", ans = map[query(1, tot, k)]); 311 } 312 else // Link 313 { 314 int x = nextI() ^ ans; 315 int y = nextI() ^ ans; 316 317 if (g[find(x)] > g[find(y)]) 318 dfs(y, x); 319 else 320 dfs(x, y); 321 } 322 } 323 } 324 } 325 /* 326 1 327 8 4 8 328 1 1 2 2 3 3 4 4 329 4 7 330 1 8 331 2 4 332 2 1 333 Q 8 7 3 334 Q 3 5 1 335 Q 10 0 0 336 L 5 4 337 L 3 2 338 L 0 7 339 Q 9 2 5 340 Q 6 1 6 341 */
@Author: YouSiki