zoukankan      html  css  js  c++  java
  • 「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;
    }
    
  • 相关阅读:
    python_控制台输出带颜色的文字方法
    模拟数据库作业
    js笔记
    CSS 笔记
    html 笔记
    必备技能-Git 使用规范流程
    python 闭包
    30个python编程技巧!
    python 面向对象
    python 线程
  • 原文地址:https://www.cnblogs.com/mangoyang/p/11524179.html
Copyright © 2011-2022 走看看