Kruskal重构树

大意:

  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
", 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 */
View Code

  

原文地址:https://www.cnblogs.com/Colythme/p/9703339.html