BZOJ 3123 [SDOI2013] 森林 - 启发式合并 主席树
Description
给你一片森林, 支持两个操作: 查询$x$到$y$的$K$大值, 连接两棵树中的两个点
Solution
对每个节点$x$动态开权值线段树, 表示从$x$到根节点路径上权值出现的次数。
查询时差分即可: $sum[x]+sum[y]-sum[lca]-sum[f[lca]]$
连边时需要启发式合并,将节点数小的接到节点数大的上去, 再遍历小的树, 并更新权值
我刚开始以为testcase是数据组数, TLE我好久,,
Code
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 #define rd read() 5 using namespace std; 6 7 const int N = 1e5; 8 9 int lson[N * 100], rson[N * 100], sum[N * 100], root[N]; 10 int n, m, T, a[N], b[N], f[N][25], head[N], tot, dep[N]; 11 int father[N], num[N], cnt, nd_num; 12 int lastans, Case; 13 14 struct edge { 15 int nxt, to; 16 }e[N << 2]; 17 18 int read() { 19 int X = 0, p = 1; char c = getchar(); 20 for(; c > '9' || c < '0'; c = getchar()) if(c == '-') p = -1; 21 for(; c >= '0' && c <= '9'; c = getchar()) X = X * 10 + c - '0'; 22 return X * p; 23 } 24 25 void add(int u, int v) { 26 e[++tot].to = v; 27 e[tot].nxt = head[u]; 28 head[u] = tot; 29 } 30 31 int find_anc(int x) { 32 return father[x] == x ? x : father[x] = find_anc(father[x]); 33 } 34 35 int find_lca(int x, int y) { 36 if(dep[x] < dep[y]) swap(x, y); 37 for(int i = 20; ~i; --i) if(dep[f[x][i]] >= dep[y]) 38 x = f[x][i]; 39 if(x == y) return x; 40 for(int i = 20; ~i; --i) if(f[x][i] != f[y][i]) 41 x = f[x][i], y = f[y][i]; 42 return f[x][0]; 43 } 44 45 int fd(int x) { 46 return lower_bound(b + 1, b + 1 + cnt, x) - b; 47 } 48 49 void ins(int &o, int now, int l, int r, int pos) { 50 o = ++nd_num; 51 sum[o] = sum[now] + 1; 52 lson[o] = lson[now]; 53 rson[o] = rson[now]; 54 if(l == r) return; 55 int mid = (l + r) >> 1; 56 if(pos <= mid) ins(lson[o], lson[now], l, mid, pos); 57 else ins(rson[o], rson[now], mid + 1, r, pos); 58 } 59 60 int query(int x, int y, int lca, int flca, int l, int r, int k) { 61 if(l == r) return l; 62 int mid = (l + r) >> 1, tmp; 63 if((tmp = sum[lson[x]] + sum[lson[y]] - sum[lson[lca]] - sum[lson[flca]]) >= k) return query(lson[x], lson[y], lson[lca], lson[flca], l, mid, k); 64 else return query(rson[x], rson[y], rson[lca], rson[flca], mid + 1, r, k - tmp); 65 } 66 67 void dfs(int u) { 68 dep[u] = dep[f[u][0]] + 1; 69 for(int i = 1; i <= 20; ++i) 70 f[u][i] = f[f[u][i - 1]][i - 1]; 71 ins(root[u], root[f[u][0]], 1, cnt, fd(a[u])); 72 for(int i = head[u]; i; i = e[i].nxt) { 73 int nt = e[i].to; 74 if(nt == f[u][0]) continue; 75 f[nt][0] = u; 76 dfs(nt); 77 } 78 } 79 80 int work() { 81 lastans = 0; tot = 0; 82 nd_num = 0; 83 /* memset(root, 0, sizeof(root)); 84 memset(lson, 0, sizeof(lson)); 85 memset(rson, 0, sizeof(rson)); 86 memset(head, 0, sizeof(head)); 87 memset(dep, 0, sizeof(dep));*/ 88 n = rd; m = rd; T = rd; 89 for(int i = 1; i <= n; ++i) b[i] = a[i] = rd; 90 sort(b + 1, b + 1 + n); 91 cnt = unique(b + 1, b + 1 + n) - b - 1; 92 for(int i = 1; i <= n; ++i) father[i] = i, num[i] = 1; 93 for(int i = 1; i <= m; ++i) { 94 int u = rd, v = rd; 95 int x = find_anc(u), y = find_anc(v); 96 father[y] = x; 97 num[x] += num[y]; 98 add(u, v); add(v, u); 99 } 100 for(int i = 1; i <= n; ++i) if(!dep[i]) dfs(i); 101 for(int i = 1; i <= T; ++i) { 102 char c = getchar(); 103 while(c != 'Q' && c != 'L') c = getchar(); 104 int u = rd ^ lastans, v = rd ^ lastans; 105 if(c == 'Q') { 106 int lca = find_lca(u, v), flca = f[lca][0], k = rd ^ lastans; 107 lastans = query(root[u], root[v], root[lca], root[flca], 1, cnt, k); 108 if(lastans > cnt || lastans < 0) return printf("F**k,WA\n"), 0; 109 lastans = b[lastans]; 110 printf("%d\n", lastans); 111 } 112 else { 113 int x = find_anc(u), y = find_anc(v); 114 if(num[x] < num[y]) { 115 swap(x, y); swap(u, v); 116 } 117 father[y] = x; 118 num[x] += num[y]; 119 f[v][0] = u; 120 add(v, u); add(u, v); 121 dfs(v); 122 } 123 } 124 return 0; 125 } 126 127 int main() 128 { 129 Case = rd; 130 work(); 131 }