WC2018 通道

好久以前开的坑.
到今天才填上.

首先考虑队第一颗树边分,然后分成两个集合\(L,R\),在第二棵树上建出虚树,在每个路径\(lca\)处统计答案,维护点集的直径只有正权很好维护.

#include <bits/stdc++.h>

using namespace std;
typedef long long ll;
typedef pair<int,int> p;
typedef pair<p,p> pp;
struct edge{
    int x;
    ll w;
    bool operator ==(const edge &_) const{
        return x==_.x&&w==_.w;
    }
    void print(){
        cerr<<"{"<<x<<","<<w<<"} ";
    }
};
typedef vector<edge> vi;
typedef vector<vector<edge> > vvi;
vi operator +(const vi &a,const vi &b){
    vi ret(a);
    ret.insert(ret.end(),b.begin(),b.end());
    return ret;
}
ostream& operator <<(ostream &ou,const p &a){
    return ou<<"["<<a.first<<","<<a.second<<"]";
}
const int N=100010;
int n;
namespace Tree3{
    vvi TG;
    int dep[N],top[N],fa[N],sz[N],son[N];
    ll dis[N];
    int getlca(int x,int y){
        while (top[x]!=top[y]){
            if (dep[top[x]]>dep[top[y]]) swap(x,y);
            y=fa[top[y]];
        }
        return dep[x]<dep[y]?x:y;
    }
    ll getdis(int x,int y){
        return dis[x]+dis[y]-2*dis[getlca(x,y)];
    }
    void Dfs(int x,int f=0){
        fa[x]=f;
        dep[x]=dep[f]+1;
        sz[x]=1;
        for (auto i:TG[x])
            if (i.x!=f){
                dis[i.x]=dis[x]+i.w;
                Dfs(i.x,x);
                sz[x]+=sz[i.x];
                if (sz[i.x]>sz[son[x]]) son[x]=i.x;
            }
    }
    void Sfd(int x,int tp,int f=0){
        top[x]=tp;
        if (son[x]) Sfd(son[x],tp,x);
        for (auto i:TG[x])
            if (i.x!=f&&i.x!=son[x]) Sfd(i.x,i.x,x);
    }
    void read(){
        TG.resize(n+1);
        for (int i=1; i<n; ++i){
            int x,y;
            ll w;
            scanf("%d%d%lld",&x,&y,&w);
            TG[x].push_back({y,w});
            TG[y].push_back({x,w});
        }
        Dfs(1);
        Sfd(1,1);
    }
}
namespace Tree2{
    const ll INF=1e18;
    vvi TG;
    int dep[N],col[N],clk,dfn[N],fa[N][17],dtime;
    ll dis[N],cost[N],ret;
    pp diameter[N];
    vector<int> E[N];
    int getlca(int x,int y){
        if (dep[x]>dep[y]) swap(x,y);
        for (int i=16; i>=0; --i) if (dep[fa[y][i]]>=dep[x]) y=fa[y][i];
        if (x==y) return x;
        for (int i=16; i>=0; --i) if (fa[y][i]!=fa[x][i]) x=fa[x][i],y=fa[y][i];
        return fa[x][0];
    }
    void Dfs(int x,int f=0){
        fa[x][0]=f;
        for (int i=1; i<17; ++i) fa[x][i]=fa[fa[x][i-1]][i-1];
        dfn[x]=++clk;
        dep[x]=dep[f]+1;
        for (auto i:TG[x])
            if (i.x!=f){
                dis[i.x]=dis[x]+i.w;
                Dfs(i.x,x);
            }
    }
    void read(){
        //cerr<<"readbegin2"<<endl;
        TG.resize(n+1);
        for (int i=1; i<n; ++i){
            int u,v;
            ll w;
            scanf("%d%d%lld",&u,&v,&w);
            TG[u].push_back({v,w});
            TG[v].push_back({u,w});
        }
        Dfs(1);
        //cerr<<"readend2"<<endl;
    }
    bool cmp(const edge &a,const edge &b){
        return dfn[a.x]<dfn[b.x];
    }
    ll calc(int a,int b){
        if (!(a&&b)) return (a||b)?-INF:-2*INF;
        if (a==b) return 0;
        //cerr<<"calc"<<a<<" "<<b<<" "<<cost[a]+cost[b]+dis[a]+dis[b]+Tree3::getdis(a,b)<<" "<<dis[a]+dis[b]<<endl;
        return cost[a]+cost[b]+dis[a]+dis[b]+Tree3::getdis(a,b);
    }
    ll calc(const p &a,const p &b){
        return max(max(calc(a.first,b.second),calc(a.first,b.first)),max(calc(a.second,b.first),calc(a.second,b.second)));
    }
    p operator +(const p &a,int b){
        ll t=calc(a.first,a.second);
        ll t2=calc(a.first,b);
        ll t3=calc(a.second,b);
        return max(t2,t3)>t?p({t2>=t3?a.first:a.second,b}):a;
    }
    p operator +(const p &a,const p &b){
        return (a+b.first)+b.second;
    }
    pp operator +(const pp &a,const pp &b){
        return {a.first+b.first,a.second+b.second};
    }
    p tr(int x){
        return {x,x};
    }
    int tim,vis[N],faf[N];
    void dfs(int x){
        //cerr<<"dfs on virtual tree:"<<x<<" "<<dis[x]<<endl;
        diameter[x]={tr(col[x]&1?x:0),tr(col[x]&1?0:x)};
        //cerr<<diameter[x].first<<" "<<diameter[x].second<<" "<<ret<<endl;
        for (auto i:E[x]){
            dfs(i);
            ret=max(ret,calc(diameter[x].first,diameter[i].second)-dis[x]*2);
            ret=max(ret,calc(diameter[x].second,diameter[i].first)-dis[x]*2);
            //cerr<<"aftmerge"<<x<<" "<<i<<" "<<diameter[x].first<<" "<<diameter[x].second<<" "<<ret<<" "<<dis[x]<<endl;
            diameter[x]=diameter[x]+diameter[i];
            
        }
        faf[x]=0;
        E[x].clear();
        //cerr<<"endi"<<x<<" "<<diameter[x].first<<" "<<diameter[x].second<<" "<<ret<<endl;
    }
    ll build_virtual_tree(vi a){
        sort(a.begin(),a.end(),cmp);
        stack<int> s;
        int rt=a[0].x;
        ret=0;
        vector<int> vim;
        for (auto i:a){
            vim.push_back(i.x);
            if (s.size()){
                int lca=getlca(s.top(),i.x);
                vim.push_back(lca);
                //cerr<<"build"<<i.x<<" "<<lca<<" "<<faf[1]<<endl;
                if (dep[lca]<dep[rt]) rt=lca;
                while (dep[faf[s.top()]]>dep[lca]) s.pop();
                bool cd=(faf[s.top()]!=lca);
                if (cd) faf[lca]=faf[s.top()];
                if (s.top()!=lca) faf[s.top()]=lca;
                s.pop();
                if (cd) s.push(lca);
                faf[i.x]=lca;
            }
            s.push(i.x);
        }
        ++tim;
        for (auto i:vim)
            if (vis[i]<tim){
                vis[i]=tim;
                //cerr<<"fa"<<i<<" "<<faf[i]<<endl;
                E[faf[i]].push_back(i);
            }
        //cerr<<"ESZE"<<E[rt].size()<<" "<<rt<<endl;
        //exit(0);
        dfs(rt);
        return ret;
    }
    ll main(vi &u,vi &v){
        if (!(u.size()&&v.size())) return -INF;
        ++dtime;
        for (auto i:u){
            col[i.x]=dtime;
            cost[i.x]=i.w;
        }
        ++dtime;
        for (auto i:v){
            col[i.x]=dtime;
            cost[i.x]=i.w;
        }
        return build_virtual_tree(u+v);
    }
}
namespace Tree1{
    vvi G,TG;
    int sz[N<<1];
    int aa,bb,cnt,val;
    ll ans,ww;
    void dfs(int x,int f){
        for (auto i:TG[x])
            if (i.x!=f) dfs(i.x,x);
        int now=x;
        for (auto i:TG[x])
            if (i.x!=f){
                G[now].push_back({i.x,i.w});
                G[i.x].push_back({now,i.w});
                //cerr<<"cdr"<<now<<" "<<i.x<<" "<<i.w<<endl;
                ++cnt;
                G[now].push_back({cnt,0});
                G[cnt].push_back({now,0});
                //cerr<<"car"<<now<<" "<<cnt<<" "<<0<<endl;
                now=cnt;
            }
    }
    void getsz(int x,int f=0){
        sz[x]=1;
        for (auto i:G[x])
            if (i.x!=f){
                getsz(i.x,x);
                sz[x]+=sz[i.x];
            }
    }
    void dfs(int x,int f,ll len){
        if (max(val-sz[x],sz[x])<max(val-sz[aa],sz[aa])){
            aa=x;
            bb=f;
            ww=len;
        }
        for (auto i:G[x])
            if (i.x!=f) dfs(i.x,x,i.w);
    }
    void Getpoint(int x,vi &g,int f=0,ll dis=0){
        if (x<=n) g.push_back({x,dis});
        for (auto i:G[x]) if (i.x!=f) Getpoint(i.x,g,x,dis+i.w);
    }
    void BF(int x){
        //cerr<<"BF"<<x<<endl;
        getsz(x);
        //cerr<<"getend"<<endl;
        aa=x;
        bb=0;
        val=sz[x];
        if (val==1) return;
        //cerr<<"dfsbegin"<<endl;
        dfs(x,0,0);
        //cerr<<"dfsend"<<aa<<" "<<bb<<" "<<ww<<" "<<(find(G[aa].begin(),G[aa].end(),edge{bb,ww})==G[aa].end())<<endl;
        G[aa].erase(find(G[aa].begin(),G[aa].end(),edge{bb,ww}));
        G[bb].erase(find(G[bb].begin(),G[bb].end(),edge{aa,ww}));
        //cerr<<"???"<<endl;
        vi u,v;
        Getpoint(aa,u);
        Getpoint(bb,v);
        //cerr<<"U:"<<endl;
        //for (auto i:u) i.print();
        //cerr<<endl<<"V:"<<endl;
        //for (auto i:v) i.print();
        //cerr<<endl<<"What's the edge:"<<aa<<" "<<bb<<" "<<ww<<endl;
        ans=max(ans,Tree2::main(u,v)+ww);
        //cerr<<"inthisans:"<<ans<<endl;
        //exit(0);
        int tmp=bb;
        BF(aa);
        BF(tmp);
    }
    void main(){
        scanf("%d",&n);
        TG.resize(n+1);
        G.resize(2*n);
        cnt=n;
        for (int i=1; i<n; ++i){
            int u,v;
            ll w;
            scanf("%d%d%lld",&u,&v,&w);
            TG[u].push_back({v,w});
            TG[v].push_back({u,w});
        }
        Tree2::read();
        Tree3::read();


        /*for (int i=1; i<=n; ++i)
            for (int j=1; j<=n; ++j)
            cerr<<i<<" "<<j<<" "<<Tree3::getdis(i,j)<<endl;*/
        dfs(1,0);
        BF(1);
        cout<<ans;
    }
}
int main(){
    Tree1::main();
}

猜你喜欢

转载自www.cnblogs.com/Yuhuger/p/10575258.html