zoukankan      html  css  js  c++  java
  • Codeforces 1140G Double Tree 倍增 + dp

    刚开始, 我以为两个点肯定是通过树上最短路径过去的, 无非是在两棵树之间来回切换, 这个可以用倍增 + dp

    去维护它。 但是后来又发现, 它可以不通过树上最短路径过去, 我们考虑这样一种情况, 起点在奇树里面, 终点
    在偶树里面, 然后这两个点最短路径里面点到对应点的距离都很大, 这种情况下我们就需要从别的地方绕过去, 这样

    就不是走树上最短路径了, 但是如果我们将对应点的距离更新成最短距离, 上面这个倍增 + dp的方法就可行了, 所以

    我们可以用最短路去更新对应点之间的距离, 将它变成最小值。

    #include<bits/stdc++.h>
    #define LL long long
    #define fi first
    #define se second
    #define mk make_pair
    #define PLL pair<LL, LL>
    #define PLI pair<LL, int>
    #define PII pair<int, int>
    #define SZ(x) ((int)x.size())
    #define ull unsigned long long
    
    using namespace std;
    
    const int N = 3e5 + 7;
    const int inf = 0x3f3f3f3f;
    const LL INF = 0x3f3f3f3f3f3f3f3f;
    const int mod = 1000000007;
    const double eps = 1e-13;
    const double PI = acos(-1);
    
    int n, q, depth[N];
    LL d[N], gg[N], dp[N][2][2][20];
    int f[N][20];
    vector<pair<int, PLL>> G[N];
    vector<PLI> E[N];
    
    void dfs(int u, int fa, PLL dis) {
        depth[u] = depth[fa] + 1;
        if(u > 1) {
            f[u][0] = fa;
            dp[u][0][0][0] = min(dis.fi, dis.se + d[u] + d[fa]);
            dp[u][1][1][0] = min(dis.se, dis.fi + d[u] + d[fa]);
            dp[u][0][1][0] = min(dis.fi + d[fa], dis.se + d[u]);
            dp[u][1][0][0] = min(dis.se + d[fa], dis.fi + d[u]);
            for(int i = 1; i < 20; i++) f[u][i] = f[f[u][i - 1]][i - 1];
            for(int i = 1; i < 20; i++) {
                int v = f[u][i - 1];
                dp[u][0][0][i] = min(dp[u][0][0][i - 1] + dp[v][0][0][i - 1], dp[u][0][1][i - 1] + dp[v][1][0][i - 1]);
                dp[u][1][1][i] = min(dp[u][1][1][i - 1] + dp[v][1][1][i - 1], dp[u][1][0][i - 1] + dp[v][0][1][i - 1]);
                dp[u][0][1][i] = min(dp[u][0][0][i - 1] + dp[v][0][1][i - 1], dp[u][0][1][i - 1] + dp[v][1][1][i - 1]);
                dp[u][1][0][i] = min(dp[u][1][1][i - 1] + dp[v][1][0][i - 1], dp[u][1][0][i - 1] + dp[v][0][0][i - 1]);
            }
        }
        for(auto& e : G[u]) {
            if(e.fi == fa) continue;
            dfs(e.fi, u, e.se);
        }
    }
    
    int getLca(int u, int v) {
        if(depth[u] < depth[v]) swap(u, v);
        for(int i = 19; i >= 0; i--)
            if(depth[f[u][i]] >= depth[v]) u = f[u][i];
        if(u == v) return u;
        for(int i = 19; i >= 0; i--)
            if(f[u][i] != f[v][i]) u = f[u][i], v = f[v][i];
        return f[u][0];
    }
    
    PLL calc(int u, int op1, int v) {
        int dis = depth[u] - depth[v];
        LL g[2], tmp[2];
        g[op1] = 0;
        g[op1 ^ 1] = d[u];
        for(int i = 19; i >= 0; i--) {
            if(dis >> i & 1) {
                tmp[0] = g[0], tmp[1] = g[1];
                g[0] = min(tmp[0] + dp[u][0][0][i], tmp[1] + dp[u][1][0][i]);
                g[1] = min(tmp[1] + dp[u][1][1][i], tmp[0] + dp[u][0][1][i]);
                u = f[u][i];
            }
        }
        return mk(g[0], g[1]);
    }
    
    int main() {
        scanf("%d", &n);
        for(int i = 1; i <= n; i++) scanf("%lld", &d[i]);
        for(int i = 2; i <= n; i++) {
            int u, v; LL w1, w2;
            scanf("%d%d%lld%lld", &u, &v, &w1, &w2);
            G[u].push_back(mk(v, mk(w1, w2)));
            G[v].push_back(mk(u, mk(w1, w2)));
            E[u].push_back(mk(w1 + w2, v));
            E[v].push_back(mk(w1 + w2, u));
        }
        priority_queue<PLI, vector<PLI>, greater<PLI> > que;
        for(int i = 1; i <= n; i++) {
            gg[i] = d[i];
            que.push(mk(d[i], i));
        }
        while(!que.empty()) {
            int u = que.top().se;
            LL val = que.top().fi;
            que.pop();
            if(val > gg[u]) continue;
            for(auto& e : E[u]) {
                if(gg[e.se] > val + e.fi) {
                    gg[e.se] = val + e.fi;
                    que.push(mk(gg[e.se], e.se));
                }
            }
        }
        for(int i = 1; i <= n; i++) d[i] = gg[i];
        dfs(1, 0, mk(0, 0));
        scanf("%d", &q);
        while(q--) {
            int u, v;
            scanf("%d%d", &u, &v);
            int op1 = (u & 1) ? 0 : 1;
            int op2 = (v & 1) ? 0 : 1;
            if(u & 1) u = (u + 1) >> 1;
            else u >>= 1;
            if(v & 1) v = (v + 1) >> 1;
            else v >>= 1;
            int Lca = getLca(u, v);
            PLL disu = calc(u, op1, Lca);
            PLL disv = calc(v, op2, Lca);
            printf("%lld
    ", min(disu.fi + disv.fi, disu.se + disv.se));
        }
        return 0;
    }
    
    /*
    
    */
  • 相关阅读:
    CodeForces Gym 100935G Board Game DFS
    CodeForces 493D Vasya and Chess 简单博弈
    CodeForces Gym 100935D Enormous Carpet 快速幂取模
    CodeForces Gym 100935E Pairs
    CodeForces Gym 100935C OCR (水
    CodeForces Gym 100935B Weird Cryptography
    HDU-敌兵布阵
    HDU-Minimum Inversion Number(最小逆序数)
    七月馒头
    非常可乐
  • 原文地址:https://www.cnblogs.com/CJLHY/p/10606646.html
Copyright © 2011-2022 走看看