大意:
Kruskal重构树即是将正常Kruskal算法中的最小生成树的边当作点,连接两个点集,且满足大(小)根堆性质,那么求两点间经过路径长度最值即它们的LCA的点权。
证明:
对于两个集合,它们之间的路径最值即连通这两个集合的最值边,且边已经过排序,故显然满足条件。
证毕。
经典用法:
· 求两点间路径最小(大)值的最大(小)值。
· 求当前点出发,仅经过边权小(大)于等于x的边可到达的所有点。
那么求出点权最小(大)的那个代表边的节点,答案为其子树。
例题:
洛谷 - Problem 4197 - Peaks
(在线)Krusal重构树 + 主席树


1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <algorithm> 5 #include <cmath> 6 7 using namespace std; 8 9 const int MAXN = 1e05 + 10; 10 const int MAXM = 5e05 + 10; 11 const int MAXT = (MAXN << 4) + (MAXN << 2); 12 13 const int INF = 0x7fffffff; 14 15 struct LinkedForwardStar { 16 int to; 17 18 int next; 19 } ; 20 21 LinkedForwardStar Link[MAXM << 2]; 22 int Head[MAXN << 1]= {0}; 23 int size = 0; 24 25 void Insert (int u, int v) { 26 Link[++ size].to = v; 27 Link[size].next = Head[u]; 28 29 Head[u] = size; 30 } 31 32 int Root; 33 34 int N, M, Q; 35 36 int Height[MAXN]; 37 38 struct Line { 39 int u, v; 40 int w; 41 42 Line () {} 43 44 Line (int fu, int fv, int fw) : 45 u (fu), v (fv), w (fw) {} 46 47 bool operator < (const Line& p) const { 48 return w < p.w; 49 } 50 } ; 51 52 Line Edges[MAXM]; 53 54 int Ances[MAXN << 1]; 55 56 int Find (int x) { 57 return x == Ances[x] ? x : Ances[x] = Find (Ances[x]); 58 } 59 60 int nodes; 61 62 int Val[MAXN << 1]; 63 64 void Kruskal () { 65 for (int i = 1; i <= N; i ++) 66 Ances[i] = i; 67 68 sort (Edges + 1, Edges + M + 1); 69 70 for (int i = 1; i <= M; i ++) { 71 int u = Edges[i].u; 72 int v = Edges[i].v; 73 int w = Edges[i].w; 74 75 int fu = Find (u); 76 int fv = Find (v); 77 78 if (fu == fv) 79 continue; 80 81 int newnode = ++ nodes; 82 Val[newnode] = w; 83 Ances[newnode] = Ances[fu] = Ances[fv] = nodes; 84 Insert (newnode, fu), Insert (fu, newnode); 85 Insert (newnode, fv), Insert (fv, newnode); 86 } 87 } 88 89 int Father[MAXN << 1][30]; 90 91 int Belong[MAXN]; 92 int dfsord = 0; 93 94 int fSize[MAXN << 1]; 95 int Minleft[MAXN << 1], Maxright[MAXN << 1]; 96 97 bool Vis[MAXN << 1]= {false}; 98 99 void DFS (int root, int father) { 100 Vis[root] = true; 101 fSize[root] = 0; 102 Minleft[root] = INF, Maxright[root] = 0; 103 Father[root][0] = father; 104 for (int j = 1; j <= 20; j ++) { 105 if (! Father[root][j - 1]) 106 continue; 107 108 Father[root][j] = Father[Father[root][j - 1]][j - 1]; 109 } 110 111 int cnt = 0; 112 for (int i = Head[root]; i; i = Link[i].next) { 113 int v = Link[i].to; 114 115 if (v == father) 116 continue; 117 118 DFS (v, root); 119 120 cnt ++; 121 fSize[root] += fSize[v]; 122 Minleft[root] = min (Minleft[root], Minleft[v]); 123 Maxright[root] = max (Maxright[root], Maxright[v]); 124 } 125 126 if (! cnt) { 127 Belong[++ dfsord] = root; 128 129 fSize[root] = 1; 130 Minleft[root] = dfsord; 131 Maxright[root] = dfsord; 132 } 133 } 134 135 int Findpos (int u, int minval) { 136 for (int j = 20; j >= 0; j --) 137 if (Father[u][j] && Val[Father[u][j]] <= minval) 138 u = Father[u][j]; 139 140 return u; 141 } 142 143 int Mapping[MAXN]; 144 int sizemapp = 0; 145 146 int ChiefTree[MAXT]; 147 int treenode = 0; 148 149 int Left[MAXT], Right[MAXT]; 150 int Size[MAXT]; 151 152 int Build (int left, int right) { 153 int root = ++ treenode; 154 155 Size[root] = 0; 156 157 if (left == right) 158 return root; 159 160 int mid = (left + right) >> 1; 161 162 Left[root] = Build (left, mid); 163 Right[root] = Build (mid + 1, right); 164 165 return root; 166 } 167 168 int Modify (int pre, int left, int right, int pos) { 169 int root = ++ treenode; 170 171 Left[root] = Left[pre], Right[root] = Right[pre]; 172 Size[root] = Size[pre] + 1; 173 174 if (left == right) 175 return root; 176 177 int mid = (left + right) >> 1; 178 179 if (pos <= mid) 180 Left[root] = Modify (Left[pre], left, mid, pos); 181 else 182 Right[root] = Modify (Right[pre], mid + 1, right, pos); 183 184 return root; 185 } 186 187 int Query (int Sl, int Sr, int left, int right, int k) { 188 if (left == right) 189 return Mapping[left]; 190 191 int psize = Size[Right[Sr]] - Size[Right[Sl]]; 192 193 int mid = (left + right) >> 1; 194 195 if (psize >= k) 196 return Query (Right[Sl], Right[Sr], mid + 1, right, k); 197 else 198 return Query (Left[Sl], Left[Sr], left, mid, k - psize); 199 } 200 201 int main () { 202 scanf ("%d%d%d", & N, & M, & Q); 203 nodes = N; 204 205 for (int i = 1; i <= N; i ++) { 206 scanf ("%d", & Height[i]); 207 Mapping[++ sizemapp] = Height[i]; 208 } 209 210 sort (Mapping + 1, Mapping + sizemapp + 1); 211 sizemapp = unique (Mapping + 1, Mapping + sizemapp + 1) - Mapping - 1; 212 213 for (int i = 1; i <= M; i ++) { 214 int u, v, w; 215 scanf ("%d%d%d", & u, & v, & w); 216 217 Edges[i] = Line (u, v, w); 218 } 219 220 Kruskal (); 221 222 for (int i = 1; i <= nodes; i ++) 223 if (! Vis[i]) { 224 Root = Find (i); 225 DFS (Root, 0); 226 } 227 228 ChiefTree[0] = Build (1, sizemapp); 229 for (int i = 1; i <= dfsord; i ++) { 230 int pos = lower_bound (Mapping + 1, Mapping + sizemapp, Height[Belong[i]]) - Mapping; 231 ChiefTree[i] = Modify (ChiefTree[i - 1], 1, sizemapp, pos); 232 } 233 234 for (int Case = 1; Case <= Q; Case ++) { 235 int from, minval, k; 236 scanf ("%d%d%d", & from, & minval, & k); 237 238 int maxpos = Findpos (from, minval); 239 if (fSize[maxpos] < k) { 240 puts ("-1"); 241 continue; 242 } 243 244 int ans = Query (ChiefTree[Minleft[maxpos] - 1], ChiefTree[Maxright[maxpos]], 1, sizemapp, k); 245 246 printf ("%d\n", ans); 247 } 248 249 return 0; 250 } 251 252 /* 253 10 11 4 254 1 2 3 4 5 6 7 8 9 10 255 1 4 4 256 2 5 3 257 9 8 2 258 7 8 10 259 7 1 4 260 6 7 1 261 6 4 8 262 2 1 5 263 10 8 10 264 3 4 7 265 3 4 6 266 1 5 2 267 1 5 6 268 1 5 8 269 8 9 2 270 */