#边分治,虚树,欧拉序,LCA#洛谷 4220 [WC2018] 通道

题目传送门


分析

实际上就是要找到一对 \((x,y)\) 使得 \(d1(x,y)+d2(x,y)+d3(x,y)\) 最大。

考虑对第一棵树三度化之后进行边分治,那么 \(d1(x,y)=d1[x]+d1[y]+w\)

如果第二棵树和第三棵树均以 \(1\) 为根,那么求的值转化为 \(d1[x]+d2[x]+d3[x]+d1[y]+d2[y]+d3[y]+w-2*d2[lca(x,y)]-2*d3[lca(x,y)]\)

也就是求 \(d[x]+d[y]+w-2*d2[lca(x,y)]-2*d3[lca(x,y)]\)

对于第二棵树建立虚树,边分治的左半部分染白,右半部分染黑,那么答案相当于是两棵子树在枚举 lca 时的黑白配对。

由于边权非负,固定 \(w-2*d2[lca(x,y)]\) 后相当于对 \(d[x]+d[y]-2*d3[lca(x,y)]\) 求最大值,可以认为是 \(x\)\(x'\) 有一条边权为 \(d1[x]+d2[x]\) 的虚拟边。

相当于是直径的两个端点,而边权非负保证了直径端点的可合并性,那么维护子树内直径的两个端点就能求出答案。


代码

#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
const int N=200011; typedef long long lll; lll s[N],dis[N],d[N],ans; struct node{int y; lll w; int next;}e[N<<1],E[N]; vector<pair<int,lll> >G[N];
int n,lg[N],two[N],deg[N],ext,et=1,as[N],SIZ,vis[N<<1],hs[N],dfn[N],nfd[N],siz[N],col[N],Et=1,part,edge,len[2],dep[N],f[N][18],tot,q[2][N];
int MIN(int x,int y){return dep[x]<dep[y]?x:y;}
int lca(int x,int y){
    int l=dfn[x],r=dfn[y];
    if (l>r) l^=r,r^=l,l^=r;
    int z=lg[r-l+1];
    return MIN(f[l][z],f[r-two[z]+1][z]);
}
lll dist(int x,int y){return s[x]+s[y]-2*dis[lca(x,y)];}
struct rec{
    int x,y; lll d;
    rec operator +(const rec &t)const{
        rec a=(rec){x,y,d},b=t,ans=a.d>b.d?a:b;
        if (a.x&&b.x){
            lll D=dist(a.x,b.x);
            if (ans.d<D) ans.d=D,ans.x=a.x,ans.y=b.x;
        }
        if (a.x&&b.y){
            lll D=dist(a.x,b.y);
            if (ans.d<D) ans.d=D,ans.x=a.x,ans.y=b.y;
        }
        if (a.y&&b.x){
            lll D=dist(a.y,b.x);
            if (ans.d<D) ans.d=D,ans.x=a.y,ans.y=b.x;
        }
        if (a.y&&b.y){
            lll D=dist(a.y,b.y);
            if (ans.d<D) ans.d=D,ans.x=a.y,ans.y=b.y;
        }
        return ans;
    }
};
lll calc(rec x,rec y){
    lll ans=0;
    if (x.x&&y.x) ans=max(ans,dist(x.x,y.x));
    if (x.x&&y.y) ans=max(ans,dist(x.x,y.y));
    if (x.y&&y.x) ans=max(ans,dist(x.y,y.x));
    if (x.y&&y.y) ans=max(ans,dist(x.y,y.y));
    return ans;
}
struct Virtual_Tree{
    node e[N],E[N]; lll dis[N],wdiv; rec dp[N][2];
    int v[N],a[N],vst[N],vtop,nfd[N],dfn[N],dep[N],tot,f[N][18],as[N],hs[N],et=1,Et;
    int MIN(int x,int y){return dep[x]<dep[y]?x:y;}
    void Pro_st(){
		for (int i=1;i<=tot;++i) f[i][0]=nfd[i];
    	for (int j=1;j<=lg[tot];++j)
    		for (int i=1;i+two[j]-1<=tot;++i)
        		f[i][j]=MIN(f[i][j-1],f[i+two[j-1]][j-1]);
	}
    int lca(int x,int y){
        int l=dfn[x],r=dfn[y];
        if (l>r) l^=r,r^=l,l^=r;
        int z=lg[r-l+1];
        return MIN(f[l][z],f[r-two[z]+1][z]);
    }
    void add(int x,int y,lll w){E[++Et]=(node){y,w,hs[x]},hs[x]=Et;}
    void Insert(int x){
        if (!vtop) {vst[++vtop]=x; return;}
        int Lca=lca(x,vst[vtop]);
        for (;vtop>1&&dep[Lca]<dep[vst[vtop-1]];--vtop)
            add(vst[vtop-1],vst[vtop],dis[vst[vtop]]-dis[vst[vtop-1]]);
        if (dep[Lca]<dep[vst[vtop]]) add(Lca,vst[vtop],dis[vst[vtop]]-dis[Lca]),--vtop;
        if (vst[vtop]!=Lca) vst[++vtop]=Lca;
        vst[++vtop]=x;
    }
    void dfs(int x){
        if (v[x]){
            dp[x][col[x]]=(rec){x,x,dist(x,x)};
            dp[x][col[x]^1]=(rec){0,0,0};
        }else dp[x][0]=dp[x][1]=(rec){0,0,0};
        for (int i=hs[x];i;i=E[i].next){
            dfs(E[i].y);
            ans=max(ans,calc(dp[x][0],dp[E[i].y][1])-2*dis[x]+wdiv);
            ans=max(ans,calc(dp[x][1],dp[E[i].y][0])-2*dis[x]+wdiv);
            dp[x][0]=dp[x][0]+dp[E[i].y][0];
            dp[x][1]=dp[x][1]+dp[E[i].y][1];
        }
        hs[x]=0;
    }
    void doit(){
        int m=len[0]+len[1];
        for (int i=1;i<=len[0];++i) a[i]=q[0][i];
        for (int i=1;i<=len[1];++i) a[i+len[0]]=q[1][i];
        for (int i=1;i<=m;++i) v[a[i]]=1;
        vtop=Et=0,a[++m]=1;
		sort(a+1,a+1+m,[this](int x,int y){return dfn[x]<dfn[y];});
        m=unique(a+1,a+1+m)-a-1;
		for (int i=1;i<=m;++i) Insert(a[i]);
		for (;vtop>1;--vtop) add(vst[vtop-1],vst[vtop],dis[vst[vtop]]-dis[vst[vtop-1]]);
		dfs(1);
        for (int i=1;i<=m;++i) v[a[i]]=0;
    }
    void dfs(int x,int fa){
        nfd[++tot]=x,dfn[x]=tot,dep[x]=dep[fa]+1,s[x]+=dis[x];
        for (int i=as[x];i;i=e[i].next) if (e[i].y!=fa)
            dis[e[i].y]=dis[x]+e[i].w,dfs(e[i].y,x),nfd[++tot]=x;
    }
}Tre;
void ADD(int x,int y,lll w){
    e[++et]=(node){y,w,as[x]},as[x]=et;
    e[++et]=(node){x,w,as[y]},as[y]=et;
}
void DFS(int x,int fa){
    if (deg[x]>(x!=1)+2){
        int lst=x,D=deg[x]-(x!=1);
        for (pair<int,lll> t:G[x])
        if (t.first!=fa){
            if (D<3) ADD(lst,t.first,t.second);
            else{
                ADD(lst,t.first,t.second);
                ADD(lst,++ext,0),lst=ext;
            }
            DFS(t.first,x),--D;
        }
    }else{
        for (pair<int,lll> t:G[x]) if (t.first!=fa)
            ADD(x,t.first,t.second),DFS(t.first,x);
    }
}
void Dfs(int x,int fa){
    siz[x]=1;
    for (int i=as[x];i;i=e[i].next)
    if (e[i].y!=fa&&!vis[i]){
        Dfs(e[i].y,x),siz[x]+=siz[e[i].y];
        int t=max(siz[e[i].y],SIZ-siz[e[i].y]);
        if (t<part) part=t,edge=i;
    }
}
void dfscol(int x,int fa,int Col){
    if (x<=n) q[Col][++len[Col]]=x,col[x]=Col;
    for (int i=as[x];i;i=e[i].next)
        if (e[i].y!=fa&&!vis[i]) d[e[i].y]=d[x]+e[i].w,dfscol(e[i].y,x,Col);
}
void Dp(int x){
    if (SIZ<2) return;
    part=SIZ,Dfs(x,0),vis[edge]=vis[edge^1]=1;
    int x1=e[edge].y,x2=e[edge^1].y,part1=siz[x1],part2=SIZ-siz[x1];
    len[0]=len[1]=d[x1]=d[x2]=0,Tre.wdiv=e[edge].w;
    dfscol(x1,x2,0),dfscol(x2,x1,1);
    if (!len[0]&&!len[1]) return;
    else if (!len[0]&&len[1]) SIZ=part2,Dp(x2);
    else if (len[0]&&!len[1]) SIZ=part1,Dp(x1);
    else{
        for (int i=1;i<=len[0];++i) s[q[0][i]]+=d[q[0][i]];
        for (int i=1;i<=len[1];++i) s[q[1][i]]+=d[q[1][i]];
        Tre.doit();
        for (int i=1;i<=len[0];++i) s[q[0][i]]-=d[q[0][i]];
        for (int i=1;i<=len[1];++i) s[q[1][i]]-=d[q[1][i]];
        SIZ=part1,Dp(x1),SIZ=part2,Dp(x2);
    }
}
void dfs(int x,int fa){
    nfd[++tot]=x,dfn[x]=tot,dep[x]=dep[fa]+1,s[x]+=dis[x];
    for (int i=hs[x];i;i=E[i].next) if (E[i].y!=fa)
        dis[E[i].y]=dis[x]+E[i].w,dfs(E[i].y,x),nfd[++tot]=x;
}
int main(){
    ios::sync_with_stdio(0);
    cin.tie(0),cout.tie(0);
    cin>>n,ext=n,lg[0]=-1,two[0]=1;
    for (int i=1;i<N;++i) lg[i]=lg[i>>1]+1;
    for (int i=1;i<=lg[N-1];++i) two[i]=two[i-1]<<1;
    for (int i=1;i<n;++i){
        int x,y; lll w; cin>>x>>y>>w;
        G[x].push_back(make_pair(y,w)),++deg[x];
        G[y].push_back(make_pair(x,w)),++deg[y];
    }
    for (int i=1;i<n;++i){
        int x,y; lll w; cin>>x>>y>>w;
        Tre.e[++Tre.et]=(node){y,w,Tre.as[x]},Tre.as[x]=Tre.et;
        Tre.e[++Tre.et]=(node){x,w,Tre.as[y]},Tre.as[y]=Tre.et;
    }
    for (int i=1;i<n;++i){
        int x,y; lll w; cin>>x>>y>>w;
        E[++Et]=(node){y,w,hs[x]},hs[x]=Et;
        E[++Et]=(node){x,w,hs[y]},hs[y]=Et;
    }
    dfs(1,0),DFS(1,0),Tre.dfs(1,0),Tre.Pro_st();
    for (int i=1;i<=tot;++i) f[i][0]=nfd[i];
    for (int j=1;j<=lg[tot];++j)
    for (int i=1;i+two[j]-1<=tot;++i)
        f[i][j]=MIN(f[i][j-1],f[i+two[j-1]][j-1]);
    SIZ=ext,Dp(1);
    cout<<ans;
	return 0;
}
posted @ 2025-08-26 14:26  lemondinosaur  阅读(10)  评论(0)    收藏  举报