LOJ#2553 暴力写挂

题意:给定两棵树T1,T2,求d1[x] + d1[y] - d1[lca1(x, y)] - d2[lca2(x, y)]的最大值。

解:考虑把上面这个毒瘤东西化一下。发现它就是T1中x,y到根的路径并 - T2中x,y到根的路径交。

也就是T1中的一个三叉状路径和T2中lca到根的路径。

根据情报中心的套路,把这个东西 * 2,发现就是d1[x] + d1[y] + dis1(x, y) - d2[x] - d2[y] + dis2(x, y)

令val[i] = d1[i] - d2[i],我们就要令val[x] + val[y] + dis1(x, y) + dis2(x, y)最大。

考虑在T1上边分治,这样的话dis1(x, y) = d[x] + d[y] + e。e是分治边的长度。

在T2上把T1这次分治的点全部提出来建虚树。我们不妨把每个T1的节点挂到对应的虚树节点上,边权为val[x] + d[x],那么我们就是要在虚树上挂的点中找到两个异色节点,使得它们距离最远。

此时我们有一个非常优秀的O(n)DFS算法......但是我就是SB中的SB中的SB,把这个问题搞成了nlogn。这个解决之后本题就做完了。为了卡常用了优秀的zkw线段树。

  1 #include <bits/stdc++.h>
  2 
  3 #define forson(x, i) for(register int i = e[x]; i; i = edge[i].nex)
  4 
  5 #define add(x, y, z) edge[++tp].v = y; edge[tp].len = z; edge[tp].nex = e[x]; e[x] = tp
  6 #define ADD(x, y) EDGE[++TP].v = y; EDGE[TP].nex = E[x]; E[x] = TP
  7 
  8 typedef long long LL;
  9 const int N = 800010;
 10 const LL INF = 4e18;
 11 
 12 inline char gc() {
 13     static char buf[N], *p1(buf), *p2(buf);
 14     if(p1 == p2) p2 = (p1 = buf) + fread(buf, 1, N, stdin);
 15     return p1 == p2 ? EOF : *p1++;
 16 }
 17 
 18 template <class T> inline void read(T &x) {
 19     x = 0;
 20     register char c(gc());
 21     bool f(false);
 22     while(c < '0' || c > '9') {
 23         if(c == '-') f = true;
 24         c = gc();
 25     }
 26     while(c >= '0' && c <= '9') {
 27         x = x * 10 + c - 48;
 28         c = gc();
 29     }
 30     if(f) x = (~x) + 1;
 31     return;
 32 }
 33 
 34 struct Edge {
 35     int nex, v;
 36     bool vis;
 37     LL len;
 38 }edge[N << 1], EDGE[N << 1]; int tp = 1, TP;
 39 
 40 int pw[N << 1], n, e[N], Cnt, _n, small, root, imp[N], K, use[N], Time, stk[N], top, E[N], RT, POS[N], NUM, SIZ[N], ID[N], vis[N], siz[N];
 41 LL val[N], ans = -INF, d[N], VAL[N], H[N], C[N], W[N];
 42 std::vector<int> G[N];
 43 std::vector<LL> Len[N];
 44 
 45 namespace seg2 {
 46     LL large[N << 2];
 47     void build(int l, int r, int o) {
 48         if(l == r) {
 49             large[o] = VAL[ID[r]];
 50             //if(F) printf("p = %d x = %d val = %lld \n", r, ID[r], VAL[ID[r]]);
 51             return;
 52         }
 53         int mid((l + r) >> 1);
 54         build(l, mid, o << 1);
 55         build(mid + 1, r, o << 1 | 1);
 56         large[o] = std::max(large[o << 1], large[o << 1 | 1]);
 57         return;
 58     }
 59     LL getMax(int L, int R, int l, int r, int o) {
 60         if(L <= l && r <= R) {
 61             return large[o];
 62         }
 63         LL ans = -INF;
 64         int mid((l + r) >> 1);
 65         if(L <= mid) ans = getMax(L, R, l, mid, o << 1);
 66         if(mid < R) ans = std::max(ans, getMax(L, R, mid + 1, r, o << 1 | 1));
 67         return ans;
 68     }
 69 }
 70 
 71 namespace seg {
 72     LL large[N << 2];
 73     int lm;
 74     inline void build(int n) {
 75         lm = 1; n += 2;
 76         while(lm < n) lm <<= 1;
 77         large[lm] = -INF;
 78         for(register int i = 1; i <= n; i++) {
 79             large[i + lm] = VAL[ID[i]];
 80         }
 81         for(register int i = n + 1; i < lm; i++) {
 82             large[i + lm] = -INF;
 83         }
 84         for(int i = lm - 1; i >= 1; i--) {
 85             large[i] = std::max(large[i << 1], large[i << 1 | 1]);
 86         }
 87         return;
 88     }
 89     inline LL getMax(int L, int R) {
 90         LL ans = -INF;
 91         for(int s = lm + L - 1, t = lm + R + 1; s ^ t ^ 1; s >>= 1, t >>= 1) {
 92             if(t & 1) {
 93                 ans = std::max(ans, large[t ^ 1]);
 94             }
 95             if((s & 1) == 0) {
 96                 ans = std::max(ans, large[s ^ 1]);
 97             }
 98         }
 99         return ans;
100     }
101 }
102 
103 namespace t1 {
104     int e[N], pos2[N], ST[N << 1][20], num2, deep[N];
105     LL d[N];
106     Edge edge[N << 1]; int tp;
107     void DFS_1(int x, int f) {
108         deep[x] = deep[f] + 1;
109         pos2[x] = ++num2;
110         ST[num2][0] = x;
111         forson(x, i) {
112             int y(edge[i].v);
113             if(y == f) continue;
114             d[y] = d[x] + edge[i].len;
115             DFS_1(y, x);
116             ST[++num2][0] = x;
117         }
118         return;
119     }
120     inline void prework() {
121         for(register int j(1); j <= pw[num2]; j++) {
122             for(register int i(1); i + (1 << j) - 1 <= num2; i++) {
123                 if(deep[ST[i][j - 1]] < deep[ST[i + (1 << (j - 1))][j - 1]]) {
124                     ST[i][j] = ST[i][j - 1];
125                 }
126                 else {
127                     ST[i][j] = ST[i + (1 << (j - 1))][j - 1];
128                 }
129             }
130         }
131         return;
132     }
133     inline int lca(int x, int y) {
134         x = pos2[x], y = pos2[y];
135         if(x > y) std::swap(x, y);
136         int t(pw[y - x + 1]);
137         if(deep[ST[x][t]] < deep[ST[y - (1 << t) + 1][t]]) {
138             return ST[x][t];
139         }
140         else {
141             return ST[y - (1 << t) + 1][t];
142         }
143     }
144     inline LL dis(int x, int y) {
145         return d[x] + d[y] - 2 * d[lca(x, y)];
146     }
147 }
148 
149 void rebuild(int x, int f) {
150     int temp(0);
151     for(register int i(0); i < G[x].size(); i++) {
152         int y = G[x][i];
153         LL len = Len[x][i];
154         if(y == f) continue;
155         if(!temp) {
156             add(x, y, len);
157             add(y, x, len);
158             temp = x;
159         }
160         else if(i == G[x].size() - 1) {
161             add(temp, y, len);
162             add(y, temp, len);
163         }
164         else {
165             add(temp, ++Cnt, 0);
166             add(Cnt, temp, 0);
167             temp = Cnt;
168             add(temp, y, len);
169             add(y, temp, len);
170         }
171         d[y] = d[x] + len;
172         rebuild(y, x);
173     }
174     return;
175 }
176 
177 void getroot(int x, int f) {
178     siz[x] = 1;
179     //printf("getroot : x = %d \n", x);
180     forson(x, i) {
181         int y(edge[i].v);
182         if(y == f || edge[i].vis) continue;
183         getroot(y, x);
184         if(small > std::max(siz[y], _n - siz[y])) {
185             small = std::max(siz[y], _n - siz[y]);
186             root = i;
187         }
188         siz[x] += siz[y];
189     }
190     //printf("siz %d = %d \n", x, siz[x]);
191     return;
192 }
193 
194 void DFS_1(int x, int f, int flag) {
195     siz[x] = 1;
196     //printf("x = %d d = %lld \n", x, d[x]);
197     if(!flag && x <= n) {
198         imp[++K] = x;
199         vis[x] = Time;
200         //if(F) printf("vis %d = Time \n", x);
201     }
202     else if(flag && x <= n) {
203         imp[++K] = x;
204     }
205     forson(x, i) {
206         int y(edge[i].v);
207         if(y == f || edge[i].vis) continue;
208         d[y] = d[x] + edge[i].len;
209         DFS_1(y, x, flag);
210         siz[x] += siz[y];
211     }
212     return;
213 }
214 
215 inline void work(int x) {
216     if(use[x] == Time) return;
217     use[x] = Time;
218     E[x] = 0;
219     return;
220 }
221 
222 inline bool cmp(const int &a, const int &b) {
223     return t1::pos2[a] < t1::pos2[b];
224 }
225 
226 inline void build_t() {
227     std::sort(imp + 1, imp + K + 1, cmp);
228     K = std::unique(imp + 1, imp + K + 1) - imp - 1;
229     work(imp[1]);
230     stk[top = 1] = imp[1];
231     for(register int i(2); i <= K; i++) {
232         int x = imp[i], y = t1::lca(x, stk[top]);
233         work(x); work(y);
234         while(top > 1 && t1::pos2[y] <= t1::pos2[stk[top - 1]]) {
235             ADD(stk[top - 1], stk[top]);
236             top--;
237         }
238         if(y != stk[top]) {
239             ADD(y, stk[top]);
240             stk[top] = y;
241         }
242         stk[++top] = x;
243     }
244     while(top > 1) {
245         ADD(stk[top - 1], stk[top]);
246         top--;
247     }
248     RT = stk[top];
249     return;
250 }
251 
252 void dfs_2(int x) {
253     //printf("dfs_2 x = %d \n", x);
254     SIZ[x] = 1;
255     POS[x] = ++NUM;
256     ID[NUM] = x;
257     if(vis[x] == Time) VAL[x] = t1::d[x] + val[x] + d[x];
258     else VAL[x] = -INF;
259     /*if(F && x == 3) {
260         printf("VAL 3 = %lld + %lld + %lld \n", t1.d[x], val[x], d[x]);
261     }*/
262     C[x] = VAL[x];
263     for(register int i(E[x]); i; i = EDGE[i].nex) {
264         int y = EDGE[i].v;
265         dfs_2(y);
266         SIZ[x] += SIZ[y];
267         C[x] = std::max(C[x], C[y]);
268     }
269     //if(F) printf("x = %d VAL = %lld  C = %lld \n", x, VAL[x], C[x]);
270     return;
271 }
272 
273 void dfs_3(int x, int f) {
274     if(f) {
275         /// cal H[x]
276         H[x] = seg::getMax(POS[f], POS[x] - 1);
277         if(POS[x] + SIZ[x] < POS[f] + SIZ[f]) {
278             H[x] = std::max(H[x], seg::getMax(POS[x] + SIZ[x], POS[f] + SIZ[f] - 1));
279         }
280         W[x] = std::max(W[f], H[x] - 2 * t1::d[f]);
281     }
282     else {
283         H[x] = W[x] = -INF;
284     }
285     //if(F) printf("x = %d H = %lld W = %lld \n", x, H[x], W[x]);
286     for(register int i(E[x]); i; i = EDGE[i].nex) {
287         int y(EDGE[i].v);
288         dfs_3(y, x);
289     }
290     return;
291 }
292 
293 void DFS_4(int x, int f, LL v) {
294     /// ask
295     if(x <= n) {
296         VAL[x] = t1::d[x] + val[x] + d[x] + v;
297         ans = std::max(ans, VAL[x] + W[x]);
298         ans = std::max(ans, VAL[x] + C[x] - 2 * t1::d[x]);
299     }
300     forson(x, i) {
301         int y(edge[i].v);
302         if(y == f || edge[i].vis) continue;
303         DFS_4(y, x, v);
304     }
305     return;
306 }
307 
308 void e_div(int x) {
309     if(_n == 1) {
310         ans = std::max(ans, val[x] << 1);
311         return;
312     }
313     small = N;
314     getroot(x, 0);
315     edge[root].vis = edge[root ^ 1].vis = 1;
316 
317     x = edge[root].v;
318     int y = edge[root ^ 1].v;
319     if(siz[x] < _n - siz[x]) std::swap(x, y);
320 
321     //if(F) printf("div %d %d  _n = %d \n", x, y, _n);
322 
323     ///
324     d[x] = d[y] = 0;
325     TP = K = 0;
326     Time++;
327     DFS_1(x, 0, 0);
328     DFS_1(y, 0, 1);
329     /// build virtue trEE
330     build_t();
331     //printf("v_t build over \n");
332     /// prework
333     NUM = 0;
334     dfs_2(RT);
335     //printf("dfs_2 over \n");
336     seg::build(NUM);
337     //printf("seg build over \n");
338     dfs_3(RT, 0);
339     DFS_4(y, 0, edge[root].len);
340 
341     //if(F) printf("ans = %d \n", ans);
342 
343     _n = siz[x];
344     e_div(x);
345     _n = siz[y];
346     e_div(y);
347     return;
348 }
349 
350 int main() {
351 
352     W[0] = -INF;
353     read(n);
354     LL z;
355     for(register int i(1), x, y; i < n; i++) {
356         read(x); read(y); read(z);
357         G[x].push_back(y);
358         G[y].push_back(x);
359         Len[x].push_back(z);
360         Len[y].push_back(z);
361     }
362     for(register int i(1), x, y; i < n; i++) {
363         read(x); read(y); read(z);
364         t1::edge[++t1::tp].v = y;
365         t1::edge[t1::tp].len = z;
366         t1::edge[t1::tp].nex = t1::e[x];
367         t1::e[x] = t1::tp;
368         t1::edge[++t1::tp].v = x;
369         t1::edge[t1::tp].len = z;
370         t1::edge[t1::tp].nex = t1::e[y];
371         t1::e[y] = t1::tp;
372     }
373     for(register int i = 2; i <= n * 2; i++) {
374         pw[i] = pw[i >> 1] + 1;
375     }
376     t1::DFS_1(1, 0);
377     t1::prework();
378 
379     Cnt = n;
380     rebuild(1, 0);
381     for(register int i(1); i <= n; i++) {
382         val[i] = d[i] - t1::d[i];
383     }
384     /// ans = val[i] + val[j] + t0.dis(i, j) + t1.dis(i, j);
385     _n = Cnt;
386     e_div(1);
387 
388     printf("%lld\n", ans >> 1);
389     return 0;
390 }
AC代码

讲一下我的做法。考虑到两个点的距离是d + d - 2 * lca,我们预处理某一颜色的节点,然后枚举另一个颜色的所有点。

由于开店的启发,我们可以把每个点往上更新链,然后每个点往上查询链。

进而发现,查询全是静态的,所以可以预处理出一个点到根路径上的max,变成单点查询。

设VAl[x]为挂上的节点x的深度。C[x]为x的子树中的最大VAL值。

设H[x]为(subtree(fa[x]) \ subtree(x)的最大VAL值) - 2 * VAL[x],W[x]为x到根路径上的最大H值。

那么对于一个点x,它只要和W[x],C[x] - 2 * VAL[x]拼起来就能得到跟它相关的最远点对距离了。

复杂度在于求H[x]的时候使用DFS序 + RMQ,写了一个log。所以总复杂度是nlog2n。

猜你喜欢

转载自www.cnblogs.com/huyufeifei/p/10714846.html