「WC2018」通道

「WC2018」通道

解题思路:

问题要最大化三棵树上的路径和,码码码就完事了。

第一棵树上边分,对于每一个边分中心 (mid),钦点边左边的联通块为黑色,右边联通块为白色,令

[f1(x)=egin{cases} dis1(x,mid) & color(x)=black \ dis1(x,mid) +weight(mid) & color(x) = white \ 0 & otherwiseend{cases} ]

对于这两个联通块的点建第二棵树上的虚树 (T2)

[f2(x)= egin{cases} 0 & color(x) = none \ dep2(x) & otherwiseend{cases} ]

那么遍历 (T2)(k) 个节点时要计算的贡献就是

[max{f1(x)+f1(y)+f2(x)+f2(y)-dis3(x,u)} -2dep2(k) \ [color(x)=black,color = white,x,yin subtree(k)] ]

那么把 (f1(x)+f2(x)) 看做点权,维护在第三棵树上异色点对端点点权加上边权的最值,经典的直径合并套路,为了保证异色点,需要维护同色点对的直径。

复杂度视情况 (mathcal O(nlog n)) 或者 (mathcal O(nlog^2n))

code

/*program by mangoyang*/
#include <bits/stdc++.h>
#define inf ((ll)(1e18))
#define Max(a, b) ((a) > (b) ? (a) : (b))
#define Min(a, b) ((a) < (b) ? (a) : (b))
typedef long long ll;
using namespace std;
template <class T>
inline void read(T &x){
	int ch = 0, f = 0; x = 0;
	for(; !isdigit(ch); ch = getchar()) if(ch == '-') f = 1;
	for(; isdigit(ch); ch = getchar()) x = x * 10 + ch - 48;
	if(f) x = -x;
}
#define int ll
#define fi first
#define se second
const int N = 300005;
int dis1[N], col[N], n, ANS;
namespace tree3{
    vector<pair<int, int> > g[N];
    int f[N][21], Log[N], ddep[N], dep[N], dfn[N], tot;
    inline void addedge(int x, int y, int z){
        g[x].push_back(make_pair(y, z));
        g[y].push_back(make_pair(x, z));
    }
    inline int chkmin(int x, int y){
        return ddep[x] < ddep[y] ? x : y;
    }
    inline void dfs(int u, int fa){
        dfn[u] = ++tot, f[tot][0] = u;
        for(int i = 0; i < (int) g[u].size(); i++){
            int v = g[u][i].fi;
            if(v == fa) continue;
            ddep[v] = ddep[u] + 1;
            dep[v] = dep[u] + g[u][i].se;
            dfs(v, u), f[++tot][0] = u;
        }
    }
    inline int lca(int u, int v){
        int x = dfn[u], y = dfn[v];
        if(x > y) swap(x, y);
        int g = Log[y-x+1];
        return chkmin(f[x][g], f[y-(1<<g)+1][g]);
    }
    inline int dis3(int x, int y){
        return dep[x] + dep[y] - 2 * dep[lca(x, y)];
    }
    inline void realmain(){
        dfs(1, 0);
        for(int i = 2; i <= tot; i++) Log[i] = Log[i>>1] + 1;
        for(int j = 1; j <= 20; j++)
            for(int i = 1; i + (1 << j) - 1 <= tot; i++)
                f[i][j] = chkmin(f[i][j-1], f[i+(1<<(j-1))][j-1]);
    }
}
namespace tree2{
    vector<int> B, e[N];
    vector<pair<int, int> > g[N];
    int f[N][21], ff[N], ddep[N], Log[N], dep[N], dfn[N], st[N], top, tot;
    inline void addedge(int x, int y, int z){
        g[x].push_back(make_pair(y, z));
        g[y].push_back(make_pair(x, z));
    }
    inline int chkmin(int x, int y){
        return ddep[x] < ddep[y] ? x : y;
    }
    inline void dfs(int u, int fa){
        dfn[u] = ++tot, f[tot][0] = u;
        for(int i = 0; i < (int) g[u].size(); i++){
            int v = g[u][i].fi;
            if(v == fa) continue;
            dep[v] = dep[u] + g[u][i].se;
            ddep[v] = ddep[u] + 1;
            dfs(v, u), f[++tot][0] = u;
        }
    }
    inline int lca(int u, int v){
        int x = dfn[u], y = dfn[v];
        if(x > y) swap(x, y);
        int g = Log[y-x+1];
        return chkmin(f[x][g], f[y-(1<<g)+1][g]);
    }
    inline void realmain(){
        dfs(1, 0);
        for(int i = 2; i <= tot; i++) Log[i] = Log[i>>1] + 1;
        for(int j = 1; j <= 20; j++)
            for(int i = 1; i + (1 << j) - 1 <= tot; i++)
                f[i][j] = chkmin(f[i][j-1], f[i+(1<<(j-1))][j-1]);
    }
    inline bool cmp(int x, int y){
        return dfn[x] < dfn[y];
    }
    inline int calc(int x, int y){
        if(!x || !y) return -1;
        return dep[x] + dep[y] + tree3::dis3(x, y) + dis1[x] + dis1[y];
    }
    inline pair<int, int> getbest(pair<int, int> A, pair<int, int> B){
        pair<int, int> C = make_pair(A.fi, B.se);
        pair<int, int> D = make_pair(A.fi, B.fi);
        pair<int, int> E = make_pair(A.se, B.fi);
        pair<int, int> F = make_pair(A.se, B.se);
        if(calc(B.fi, B.se) > calc(A.fi, A.se)) A = B;
        if(calc(C.fi, C.se) > calc(A.fi, A.se)) A = C;
        if(calc(D.fi, D.se) > calc(A.fi, A.se)) A = D;
        if(calc(E.fi, E.se) > calc(A.fi, A.se)) A = E;
        if(calc(F.fi, F.se) > calc(A.fi, A.se)) A = F;
        return A;
    }
    struct node{
        pair<int, int> A, B;
        inline void reset(){
            A.fi = A.se = B.fi = B.se = 0;
        }
        friend node operator + (node left, node right){
            node res;
            res.A = getbest(left.A, right.A);
            res.B = getbest(left.B, right.B);
            return res;
        } 
        friend int operator * (node left, node right){
            return max(calc(left.A.fi, right.B.fi),
                   max(calc(left.A.fi, right.B.se),
                   max(calc(left.A.se, right.B.fi),
                   max(calc(left.A.se, right.B.se),
                   max(calc(left.B.fi, right.A.fi),
                   max(calc(left.B.fi, right.A.se),
                   max(calc(left.B.se, right.A.fi),
                   calc(left.B.se, right.A.se))))))));
             
        }
    } s[N];
    inline void append(int x, int y){
        ff[x] = y, st[++top] = x, B.push_back(x);
    }
    inline void make_tree(vector<int> &A){
        top = 0, B.clear();
        for(int i = 0; i < (int) A.size(); i++){
            int u = A[i];
            if(!top) append(u, 0);
            else{
                int x = lca(u, st[top]);                
                for(; top > 1 && ddep[st[top]] > ddep[x]; top--)
                    if(ddep[st[top-1]] < ddep[x]) ff[st[top]] = x;
                if(st[top] != x) append(x, st[top]);
                append(u, x);
            }
        }
        for(int i = 0; i < (int) B.size(); i++)
            if(B[i] > 1) e[ff[B[i]]].push_back(B[i]);
    }
    inline void dfs_for_ans(int u){
        s[u].reset();
        if(col[u] == 1) s[u].A = make_pair(u, u);
        if(col[u] == 2) s[u].B = make_pair(u, u);
        for(int i = 0; i < (int) e[u].size(); i++){
            int v = e[u][i];
            dfs_for_ans(v);
            ANS = max(ANS, s[v] * s[u] - 2 * dep[u]);
            s[u] = s[v] + s[u];
        }
    }
    inline void solve(vector<int> &A){
        if((int) A.size() <= 1) return;
        sort(A.begin(), A.end(), cmp);
        if(A[0] != 1){
            reverse(A.begin(), A.end());
            A.push_back(1);
            reverse(A.begin(), A.end());
        }
        make_tree(A), dfs_for_ans(1);
        for(int i = 0; i < (int) B.size(); i++)
            ff[B[i]] = 0, e[B[i]].clear();
    }
}
namespace tree1{
    vector<int> qwq;
    vector<pair<int, int> > g[N];
    pair<int, int> RT;
    int lst[N], vis[N], dep[N], sz[N], allsize, mnsize, cnt;
    inline void addedge(int x, int y, int z){
        g[x].push_back(make_pair(y, z));
        g[y].push_back(make_pair(x, z));
    }
    inline void append(int x, int y, int z){
        addedge(lst[x], ++cnt, 0);
        addedge(lst[x] = cnt, y, z);
    }
    inline void build(int u, int fa){
        for(int i = 0; i < (int) g[u].size(); i++){
            int v = g[u][i].fi;
            if(v == fa || v > n) continue;
            append(u, v, g[u][i].se), build(v, u);
        }
    }
    inline void dfs_pre(int u, int fa){
        for(int i = 0; i < (int) g[u].size(); i++){
            int v = g[u][i].fi;
            if(v == fa) continue;
            dep[v] = dep[u] + g[u][i].se, dfs_pre(v, u);
        }
    }
    inline void getsize(int u, int fa){
        int now = 0; sz[u] = 1;
        for(int i = 0; i < (int) g[u].size(); i++){
            int v = g[u][i].fi;
            if(v == fa || vis[v]) continue;
            getsize(v, u), sz[u] += sz[v];
            if(sz[v] > now) now = sz[v];
        }
        now = max(now, allsize - sz[u]);
        if(now < mnsize && fa)
            mnsize = now, RT = make_pair(u, fa);
    }
    inline pair<int, int> find_next_edge(int x, int y){
        allsize = y, mnsize = inf;
        getsize(x, 0); return RT;
    }
    inline void dfs_for_getpoint(int u, int fa, int d){
        if(u <= n) qwq.push_back(u), dis1[u] = d; 
        for(int i = 0; i < (int) g[u].size(); i++){
            int v = g[u][i].fi;
            if(v == fa || vis[v]) continue;
            dfs_for_getpoint(v, u, d + g[u][i].se);
        }
    }
    inline vector<int> getpoint(int x){
        qwq.clear();
        dfs_for_getpoint(x, 0, 0);
        return qwq;
    }
    inline void divide(pair<int, int> now){
        int x = now.fi, y = now.se;
        vis[x] = vis[y] = 1;
        vector<int> Ax = getpoint(x);
        vector<int> Ay = getpoint(y);
        vector<int> A;
        for(int i = 0; i < (int) Ax.size(); i++){ 
            dis1[Ax[i]] += abs(dep[x] - dep[y]);
            col[Ax[i]] = 1, A.push_back(Ax[i]);
        }
        for(int i = 0; i < (int) Ay.size(); i++) 
            col[Ay[i]] = 2, A.push_back(Ay[i]);

        tree2::solve(A);
        for(int i = 0; i < (int) A.size(); i++)
            col[A[i]] = dis1[A[i]] = 0;
        int allx = sz[x], ally = allsize - sz[x];
        if(allx > 1) vis[x] = 0, divide(find_next_edge(x, allx)), vis[x] = 1;
        if(ally > 1) vis[y] = 0, divide(find_next_edge(y, ally)), vis[y] = 1;
    }
    inline void realmain(){
        cnt = n;
        for(int i = 1; i <= n; i++) lst[i] = i;
        build(1, 0);
        for(int i = 1; i <= n; i++){
            vector<pair<int, int> > A;
            for(int j = 0; j < (int) g[i].size(); j++)
                if(g[i][j].fi > n) A.push_back(g[i][j]);
            g[i] = A;
        }
        dfs_pre(1, 0);
        if(n > 1) divide(find_next_edge(1, cnt));
    }
}
signed main(){
    read(n);
    for(int i = 1, x, y, z; i < n; i++){
        read(x), read(y), read(z);
        tree1::addedge(x, y, z);
    }
    for(int i = 1, x, y, z; i < n; i++){
        read(x), read(y), read(z);
        tree2::addedge(x, y, z);
    }
    for(int i = 1, x, y, z; i < n; i++){
        read(x), read(y), read(z);
        tree3::addedge(x, y, z);
    }
    tree3::realmain();
    tree2::realmain();
    tree1::realmain();
    cout << ANS << endl;
    return 0;
}
原文地址:https://www.cnblogs.com/mangoyang/p/11524179.html