森林 BZOJ 3123
题解:
第k大直接用主席树解决
合并利用启发式合并,将较小的连接到较大的树上
1 #include<cmath> 2 #include<cstdio> 3 #include<cstdlib> 4 #include<cstring> 5 #include<iostream> 6 #include<algorithm> 7 using namespace std; 8 const int inf = 2e9; 9 const int logn = 17; 10 const int maxn = 8e4 + 233; 11 const int maxm = 2e5; 12 int t, n, m, q; 13 int sum[maxn * 500], lc[maxn * 500], rc[maxn * 500]; 14 int rt[maxn]; 15 int tot, nex[maxm], fir[maxm], ver[maxm]; 16 int num, cnt; 17 int ans; 18 int disp[maxn]; 19 int si[maxn], dep[maxn], anc[maxn][logn + 1]; 20 int fat[maxn]; 21 int val[maxn]; 22 bool vis[maxn]; 23 inline int Get() 24 { 25 int x; 26 char c; 27 bool o = false; 28 while((c = getchar()) < '0' || c > '9') 29 if(c == '-') o = true; 30 x = c - '0'; 31 while((c = getchar()) >= '0' && c <= '9') 32 x = x * 10 + c - '0'; 33 return (o) ? -x : x; 34 } 35 inline void Reset() 36 { 37 for(int i = 1; i <= n; ++i) 38 disp[i] = val[i], fat[i] = i, si[i] = 1; 39 } 40 inline void Disperse() 41 { 42 sort(disp + 1, disp + 1 + n); 43 disp[0] = -inf; 44 for(int i = 1; i <= n; ++i) 45 if(disp[i] != disp[i - 1]) 46 disp[++num] = disp[i]; 47 for(int i = 1; i <= n; ++i) 48 val[i] = lower_bound(disp + 1, disp + 1 + num, val[i]) - disp; 49 } 50 inline void Ins(int x, int y) 51 { 52 nex[++tot] = fir[x], fir[x] = tot, ver[tot] = y; 53 } 54 inline int Find(int x) 55 { 56 return (fat[x] != x) ? fat[x] = Find(fat[x]) : x; 57 } 58 inline void Edge(int x, int y) 59 { 60 int a = Find(x), b = Find(y); 61 if(a != b) fat[a] = b, si[b] += si[a]; 62 Ins(x, y), Ins(y, x); 63 } 64 int Add(int p, int l, int r, int v) 65 { 66 int k = ++cnt; 67 sum[k] = sum[p] + 1; 68 if(l == r) return k; 69 int mi = l + r >> 1; 70 if(v <= mi) lc[k] = Add(lc[p], l, mi, v), rc[k] = rc[p]; 71 else lc[k] = lc[p], rc[k] = Add(rc[p], mi + 1, r, v); 72 return k; 73 } 74 void Build(int u, int f) 75 { 76 vis[u] = true; 77 dep[u] = dep[f] + 1; 78 anc[u][0] = f; 79 for(int i = 1; i <= logn; ++i) 80 anc[u][i] = anc[anc[u][i - 1]][i - 1]; 81 rt[u] = Add(rt[f], 1, num, val[u]); 82 for(int i = fir[u]; i; i = nex[i]) 83 { 84 int v = ver[i]; 85 if(v == f) continue; 86 Build(v, u); 87 } 88 } 89 inline void Edge() 90 { 91 for(int i = 1; i <= m; ++i) Edge(Get(), Get()); 92 } 93 inline void Build() 94 { 95 for(int i = 1; i <= n; ++i) 96 if(!vis[i]) 97 Build(i, 0); 98 } 99 inline void Link(int x, int y) 100 { 101 int a = Find(x), b = Find(y); 102 if(si[a] < si[b]) swap(x, y); 103 dep[y] = dep[x] + 1; 104 Build(y, x); 105 Ins(x, y), Ins(y, x); 106 } 107 inline int Lca(int x, int y) 108 { 109 if(dep[x] < dep[y]) swap(x, y); 110 for(int i = logn; i >= 0; --i) 111 if(dep[anc[x][i]] >= dep[y]) 112 x = anc[x][i]; 113 if(x == y) return x; 114 for(int i = logn; i >= 0; --i) 115 if(anc[x][i] != anc[y][i]) 116 { 117 x = anc[x][i]; 118 y = anc[y][i]; 119 } 120 return anc[x][0]; 121 } 122 inline int Query(int a, int b, int c, int d, int l, int r, int k) 123 { 124 if(l == r) return disp[l]; 125 int res = sum[lc[a]] + sum[lc[b]] - sum[lc[c]] - sum[lc[d]]; 126 int mi = l + r >> 1; 127 if(res >= k) return Query(lc[a], lc[b], lc[c], lc[d], l, mi, k); 128 return Query(rc[a], rc[b], rc[c], rc[d], mi + 1, r, k - res); 129 } 130 inline void Ask() 131 { 132 while(q--) 133 { 134 char c; 135 while((c = getchar()) != 'L' && c != 'Q'); 136 switch(c) 137 { 138 case 'L': 139 { 140 int x = Get() ^ ans, y = Get() ^ ans; 141 Link(x, y); 142 break; 143 } 144 case 'Q': 145 { 146 int x = Get() ^ ans, y = Get() ^ ans, k = Get() ^ ans; 147 int lca = Lca(x, y); 148 ans = Query(rt[x], rt[y], rt[lca], rt[anc[lca][0]], 1, num, k); 149 printf("%d\n", ans); 150 break; 151 } 152 } 153 } 154 } 155 int main() 156 { 157 t = Get(), n = Get(), m = Get(), q = Get(); 158 for(int i = 1; i <= n; ++i) val[i] = Get(); 159 Reset(); 160 Disperse(); 161 Edge(); 162 Build(); 163 Ask(); 164 }