【学习笔记】[WC2018]通道

注意到这一点:边权非负

首先对第一棵树进行边分治。式子变成了 D ( x ) + D ( y ) + dist2 ( x , y ) + dist3(x,y) D(x)+D(y)+\text{dist2}(x,y)+\text{dist3(x,y)} D(x)+D(y)+dist2(x,y)+dist3(x,y),显然可以对第二颗树继续分治,但是这样复杂度 O ( n log ⁡ 3 n ) O(n\log^3 n) O(nlog3n)难以通过。

假设 x , y x,y x,y在第二颗树上的最近公共祖先为 p p p,我们考虑对于 x ′ x' x x x x之间连一条边,权值为 D ( x ) + dep2(x) D(x)+\text{dep2(x)} D(x)+dep2(x),那么可以转化为求第三棵树上的最远点对问题。

想到了什么?没错,在一棵树上两个集合并集的最远点对是可以直接合并的。

那么直接在第二棵树的虚树上统计答案即可。

复杂度 O ( n log ⁡ 2 n ) O(n\log^2 n) O(nlog2n)

调了一整天代码,属实是没什么意义了。

#include<bits/stdc++.h> #define fi first #define se second #define ll long long #define db double #define pb push_back #define inf 0x3f3f3f3f3f3f3f3f using namespace std; const int N=8e5+5; int T,n,n2; int dep[N],dep2[N],vis[N],dfn[N],tp[N],tp2[N],fa[N],fa2[N],son[N],son2[N],siz2[N],siz3[N],num,c[N]; int hd[N],to[N],st[N],nxt[N],tot=1; ll dis1[N],dis2[N],dis3[N],w[N],res; vector<pair<int,ll>>g[N]; void add(int x,int y,ll z){ to[++tot]=y,w[tot]=z,st[tot]=x,nxt[tot]=hd[x],hd[x]=tot; to[++tot]=x,w[tot]=z,st[tot]=y,nxt[tot]=hd[y],hd[y]=tot; } int Lca(int x,int y){ int fx=tp[x],fy=tp[y]; while(fx!=fy){ if(dep[fx]>dep[fy])x=fa[fx]; else y=fa[fy]; fx=tp[x],fy=tp[y]; }return dep[x]<dep[y]?x:y; } int Lca2(int x,int y){ int fx=tp2[x],fy=tp2[y]; while(fx!=fy){ if(dep2[fx]>dep2[fy])x=fa2[fx]; else y=fa2[fy]; fx=tp2[x],fy=tp2[y]; }return dep2[x]<dep2[y]?x:y; } void dfs(int u,int topf){ int lst=u; for(auto v:g[u]){ if(v.fi!=topf){ n2++,add(lst,n2,0),add(n2,v.fi,v.se),lst=n2,dfs(v.fi,u); } } } void dfs2(int u,int topf){ dfn[u]=++num,fa[u]=topf,dep[u]=dep[topf]+1,siz2[u]=1; for(auto v:g[u]){ if(v.fi!=topf){ dis2[v.fi]=dis2[u]+v.se,dfs2(v.fi,u),siz2[u]+=siz2[v.fi]; if(siz2[v.fi]>siz2[son[u]])son[u]=v.fi; } } } void dfs7(int u,int topf){ tp[u]=topf; if(son[u])dfs7(son[u],topf); for(auto v:g[u]){ if(!tp[v.fi])dfs7(v.fi,v.fi); } } void dfs3(int u,int topf){ fa2[u]=topf,dep2[u]=dep2[topf]+1,siz3[u]=1; for(auto v:g[u]){ if(v.fi!=topf){ dis3[v.fi]=dis3[u]+v.se,dfs3(v.fi,u),siz3[u]+=siz3[v.fi]; if(siz3[v.fi]>siz3[son2[u]])son2[u]=v.fi; } } } void dfs8(int u,int topf){ tp2[u]=topf; if(son2[u])dfs8(son2[u],topf); for(auto v:g[u]){ if(!tp2[v.fi])dfs8(v.fi,v.fi); } } int edge,D,siz[N]; void dfs4(int u,int topf,int sz){ siz[u]=1; for(int k=hd[u];k;k=nxt[k]){ int v=to[k]; if(!vis[k]&&v!=topf){ dfs4(v,u,sz),siz[u]+=siz[v]; if(max(siz[v],sz-siz[v])<D)D=max(siz[v],sz-siz[v]),edge=k; } } } int m,p[N],s[N],cnt; vector<int>vec,g2[N]; void dfs5(int u,int topf,int C){ c[u]=C;if(u<=n)p[++m]=u; for(int k=hd[u];k;k=nxt[k]){ int v=to[k]; if(!vis[k]&&v!=topf){ dis1[v]=dis1[u]+w[k],dfs5(v,u,C); } } } bool cmp(int x,int y){ return dfn[x]<dfn[y]; } void Add(int x,int y){ if(dep[x]>dep[y])swap(x,y); g2[x].pb(y); } void build(){ for(int i=1;i<=m;i++)vec.pb(p[i]); s[cnt=1]=1,vec.pb(1);sort(p+1,p+1+m,cmp); for(int i=1;i<=m;i++){ if(p[i]==1)continue; int u=p[i],v=Lca(s[cnt],u),lst=0; if(s[cnt]==v)s[++cnt]=u; else{ while(dep[s[cnt]]>dep[v]){ if(lst)Add(s[cnt],lst); lst=s[cnt--]; } if(s[cnt]==v){ Add(lst,v),s[++cnt]=u; } else{ Add(lst,v),s[++cnt]=v,vec.pb(v),s[++cnt]=u; } } }for(int i=1;i<cnt;i++)Add(s[i],s[i+1]); } ll ask(int x,int y){ if(!x||!y||x==y)return -inf; return dis3[x]+dis3[y]-2*dis3[Lca2(x,y)]+dis1[x]+dis1[y]+dis2[x]+dis2[y]+w[edge]; } struct node{ int a,b; bool operator <(const node &r)const{ return ask(a,b)<ask(r.a,r.b); } node operator +(const node &r)const{ if(!a||!r.a)return {a+r.a,b+r.b}; return max({(node){a,r.a},(node){a,r.b},(node){b,r.a},(node){b,r.b},(node){a,b},r}); } }dp[N],dp2[N]; void dfs6(int u){ dp[u]=dp2[u]={0,0}; if(c[u]==1)dp[u]={u,u}; if(c[u]==2)dp2[u]={u,u}; for(auto v:g2[u]){ dfs6(v); ll tmp=max({ask(dp[u].a,dp2[v].a),ask(dp[u].a,dp2[v].b),ask(dp[u].b,dp2[v].a),ask(dp[u].b,dp2[v].b)}); ll tmp2=max({ask(dp2[u].a,dp[v].a),ask(dp2[u].a,dp[v].b),ask(dp2[u].b,dp[v].a),ask(dp2[u].b,dp[v].b)}); res=max(res,max(tmp,tmp2)-2*dis2[u]); dp[u]=dp[u]+dp[v],dp2[u]=dp2[u]+dp2[v]; } } void solve(int u,int sz){ if(sz==1)return; edge=-1,D=0x3f3f3f3f; dfs4(u,0,sz);vis[edge]=vis[edge^1]=1; dis1[st[edge]]=dis1[to[edge]]=0,m=0,dfs5(st[edge],0,1),dfs5(to[edge],0,2); build(),dfs6(1); for(int i=0;i<vec.size();i++)c[vec[i]]=0,g2[vec[i]].clear();vec.clear(); int tmp=edge; solve(st[tmp],sz-siz[to[tmp]]),solve(to[tmp],siz[to[tmp]]); } signed main(){ ios::sync_with_stdio(false); cin.tie(0),cout.tie(0); cin>>n,n2=n; for(int i=1;i<n;i++){ int x,y;ll z;cin>>x>>y>>z; g[x].pb({y,z}),g[y].pb({x,z}); }dfs(1,0);for(int i=1;i<=n;i++)g[i].clear(); for(int i=1;i<n;i++){ int x,y;ll z;cin>>x>>y>>z; g[x].pb({y,z}),g[y].pb({x,z}); }dfs2(1,0),dfs7(1,1);for(int i=1;i<=n;i++)g[i].clear(),son[i]=0; for(int i=1;i<n;i++){ int x,y;ll z;cin>>x>>y>>z; g[x].pb({y,z}),g[y].pb({x,z}); }dfs3(1,0),dfs8(1,1);for(int i=1;i<=n;i++)g[i].clear(); solve(1,n2);cout<<res; }

__EOF__

本文作者仰望星空的蚂蚁
本文链接https://www.cnblogs.com/cqbzly/p/17530066.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   仰望星空的蚂蚁  阅读(10)  评论(0编辑  收藏  举报  
相关博文:
阅读排行:
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· DeepSeek 开源周回顾「GitHub 热点速览」
点击右上角即可分享
微信分享提示