zoukankan      html  css  js  c++  java
  • 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 
    ", 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 
    ", 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 
    ", 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 
    ", x, d[x]);
    197     if(!flag && x <= n) {
    198         imp[++K] = x;
    199         vis[x] = Time;
    200         //if(F) printf("vis %d = Time 
    ", 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 
    ", 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 
    ", 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 
    ", 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 
    ", 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 
    ", 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 
    ");
    332     /// prework
    333     NUM = 0;
    334     dfs_2(RT);
    335     //printf("dfs_2 over 
    ");
    336     seg::build(NUM);
    337     //printf("seg build over 
    ");
    338     dfs_3(RT, 0);
    339     DFS_4(y, 0, edge[root].len);
    340 
    341     //if(F) printf("ans = %d 
    ", 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
    ", 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。


    有个T1是链且v > 0的部分分。这里我们发现T1的路径并变成了max(d1[x], d1[y]),于是考虑枚举T2中每个点作为lca,要求两个点在其子树中,且max(d1[x], d1[y])最大。显然维护一个子树最大值就好了。实测有80分呢......

    还有个迭代乱搞是随机选一个起点,每次迭代找到一个点与之贡献最大并更新那个点为新的起点。多来几次。这样也有80分呢......

    比写正解不知道高到哪里去了...

  • 相关阅读:
    Flutter实战视频-移动电商-11.首页_屏幕适配方案讲解
    Flutter实战视频-移动电商-10.首页_FlutterSwiper轮播效果制作
    Flutter实战视频-移动电商-09.首页_项目结构建立和获取数据
    Flutter实战视频-移动电商-08.Dio基础_伪造请求头获取数据
    【RQNOJ】460 诺诺的队列
    NYOJ 483 Nightmare 【广搜】+【无标记】
    冒泡,简单选择,直接插入排序(Java版)
    基于MFC与第三方类CWebPage的百度地图API开发范例
    USACO 1.2 Palindromic Squares (进制转换,回文)
    与《新走遍美国》的邂逅
  • 原文地址:https://www.cnblogs.com/huyufeifei/p/10714846.html
Copyright © 2011-2022 走看看