1. 程式人生 > >「WC2018」通道

「WC2018」通道

沒有程式碼能力...

LOJ #2339

Luogu P4220

UOJ #347


題意

給定三棵樹$ T1,T2,T3$,求一個點對$ (x,y)$使得$ T1.dist(x,y)+T2.dist(x,y)+T3.dist(x,y)$最大

每棵樹的點數為$ 10^5$,時限$ 4s$


$ Solution$

嘗試對$ T1$邊分治 

設當前分治到邊$(L,R)$

將$ L$及$ L$所在一側的點染黑,將$ R$及$ R$所在一側的點染白

問題轉化為找到一個點對$ (x,y)$使得滿足$ x$為黑點$ y$為白點

並且最大化

$ T1.dist(x,L)+T1.dist(y,R)+len(x,y)+T2.dist(x,y)+T3.dist(x,y)$

考慮將所有黑白點拿出來在$ T2$上構一棵虛樹

在虛樹上$ DP$

有一些不那麼顯然的性質:

 

設兩端均為黑色的最長路徑的兩個端點為$ (B1,B2)$,兩端均為白色的最長路徑的兩個端點為$ (W1,W2)$

則兩端異色的最長路徑的兩個端點一定在$ B1,B2,W1,W2$中出現過

 

設點集$ S$的黑色最長路徑的兩個端點為$ (B1,B2)$,點集$ T$的黑色最長路徑的兩個端點為$ (B3,B4)$

則點集$ S \cup T$的黑色最長路徑的兩個端點一定在$ B1,B2,B3,B4$中出現過

 

用這兩個性質就可以在虛樹上$ DP$了

形象化地,設我們在虛樹上列舉點對在$ T2$上的$ LCA$

則這個點對一定來自於列舉的$ LCA$的不同子樹

在每個子樹記錄黑色/白色最長路徑的端點然後合併轉移即可

時間複雜度$ O(n \ log^2 \ n)$


$my \ code$

#include<ctime>
#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<queue>
#include
<vector> #define M 500010 #define rt register int #define ll long long using namespace std; namespace fast_IO{ const int IN_LEN=10000000,OUT_LEN=10000000; char ibuf[IN_LEN],*ih=ibuf+IN_LEN,*lastin=ibuf+IN_LEN; inline char getchar_(){return (ih==lastin)&&(lastin=(ih=ibuf)+fread(ibuf,1,IN_LEN,stdin),ih==lastin)?EOF:*ih++;} } using namespace fast_IO; #define getchar() getchar_() inline ll read(){ ll x=0;char zf=1;char ch=getchar(); while(ch!='-'&&!isdigit(ch))ch=getchar(); if(ch=='-')zf=-1,ch=getchar(); while(isdigit(ch))x=x*10+ch-'0',ch=getchar();return x*zf; } void write(ll y){if(y<0)putchar('-'),y=-y;if(y>9)write(y/10);putchar(y%10+48);} void writeln(const ll y){write(y);putchar('\n');} int k,m,n,x,y,z,cnt,B,W,la;ll ans; int sorttable[M];ll dist[M]; bool cmp(int x,int y){return sorttable[x]<sorttable[y];} int sz[M],A[M],col[M];bool vis[M]; int nowmin,all,ed,sum,Root; struct node{int a;ll c;}; vector<node>e[M]; struct tree{ int F[M],L[M],N[M],a[M],dfn[M],q[M],size[M],k=1,t=0,cnt=0;ll deep[M],c[M]; int st[19][M],fa[M],lg2[M],fir[M],dep[M]; void clear(){ for(rt i=2;i<=k;i++)F[a[i]]=0,N[i]=0; F[Root]=0;k=1;t=0;cnt=0; } void add(int x,int y,ll z){ a[++k]=y;c[k]=z; if(!F[x])F[x]=k; else N[L[x]]=k; L[x]=k; } void dfs(int x,int pre){ q[++t]=x;dfn[x]=++cnt;size[x]=1;fa[x]=pre;fir[x]=t; for(rt i=F[x];i;i=N[i])if(a[i]!=pre){ deep[a[i]]=deep[x]+c[i]; dep[a[i]]=dep[x]+1; dfs(a[i],x); size[x]+=size[a[i]]; q[++t]=x; } } void rebuild_init(int x,int pre){ for(rt i=F[x];i;i=N[i])if(a[i]!=pre){ e[x].push_back({a[i],c[i]}); rebuild_init(a[i],x); } } void rebuild(){ clear(); for(rt i=1;i<=n;i++){ if(e[i].size()<=2)for(auto j:e[i])add(i,j.a,j.c*(j.a<=la)),add(j.a,i,j.c*(j.a<=la)); else { int v1=++n,v2=++n; add(i,v1,0);add(v1,i,0);add(i,v2,0);add(v2,i,0); for(rt j=0;j<e[i].size();j++)if(j&1)e[v1].push_back(e[i][j]); else e[v2].push_back(e[i][j]); } } } int mins(int x,int y){return dep[x]<dep[y]?x:y; } void LCA_init(){ for(rt i=1;i<=t;i++)st[0][i]=q[i]; for(rt i=1;i<=18;i++) for(rt j=1;j<=t;j++) st[i][j]=mins(st[i-1][j],st[i-1][min(t,j+(1<<i-1))]); for(rt i=2;i<=t;i++)lg2[i]=lg2[i>>1]+1; } inline int LCA(const int x,const int y){ int L=fir[x],R=fir[y];if(L>R)swap(L,R); const int len=lg2[R-L+1]; return mins(st[len][L],st[len][R-(1<<len)+1]); } inline ll dis(const int x,const int y){ return deep[x]+deep[y]-deep[LCA(x,y)]*2; } inline bool anc(const int x,const int y){//x是否為y祖先 return dfn[x]<=dfn[y]&&dfn[x]+size[x]-1>=dfn[y]; } }T1,T2,T3,xs; void build(int n,int *A){ xs.clear();//對於點集A在xs上建虛樹 static int q[M],sta[M];int tott=n,topp=1; static bool vis[M]; for(rt i=1;i<=n;i++)q[i]=A[i],vis[q[i]]=1; for(rt i=1;i<=n;i++)sorttable[i]=T2.dfn[q[i]]; sort(q+1,q+n+1,cmp); for(rt i=n;i>=2;i--){ int lca=T2.LCA(q[i],q[i-1]); if(!vis[lca])vis[lca]=1,q[++tott]=lca,col[lca]=0; } for(rt i=1;i<=tott;i++)sorttable[q[i]]=T2.dfn[q[i]]; sort(q+1,q+tott+1,cmp); sta[topp=1]=q[1]; for(rt i=2;i<=tott;i++){ while(topp&&!T2.anc(sta[topp],q[i]))topp--; if(topp){ ll val=-T2.deep[sta[topp]]+T2.deep[q[i]]; xs.add(sta[topp],q[i],val); }sta[++topp]=q[i]; } for(rt i=1;i<=tott;i++)vis[q[i]]=0; Root=q[1]; } void printblack(int x,int pre,ll ds=0){//黑1白2 if(x<=la)A[++sum]=x,col[x]=1,dist[x]=ds; for(rt i=T1.F[x];i;i=T1.N[i])if(T1.a[i]!=pre&&!vis[i>>1])printblack(T1.a[i],x,ds+T1.c[i]); } void printwhite(int x,int pre,ll ds=0){//黑1白2 if(x<=la)A[++sum]=x,col[x]=2,dist[x]=ds; for(rt i=T1.F[x];i;i=T1.N[i])if(T1.a[i]!=pre&&!vis[i>>1])printwhite(T1.a[i],x,ds+T1.c[i]); } void get(int x,int pre){ sz[x]=1; for(rt i=T1.F[x];i;i=T1.N[i])if(T1.a[i]!=pre&&!vis[i>>1]){ get(T1.a[i],x); const int val=abs(all-2*sz[T1.a[i]]); if(val<nowmin)nowmin=val,ed=i; sz[x]+=sz[T1.a[i]]; } } ll calc(int x,int y){//左黑右白 if(x==-1||y==-1)return -100000000000000ll; return dist[x]+dist[y]+T2.deep[x]+T2.deep[y]+T3.dis(x,y); } struct white{int x,y;}; struct black{int x,y;}; ll calcw(white x){ return dist[x.x]+dist[x.y]+T2.deep[x.x]+T2.deep[x.y]+T3.dis(x.x,x.y); } ll calcb(black x){ return dist[x.x]+dist[x.y]+T2.deep[x.x]+T2.deep[x.y]+T3.dis(x.x,x.y); } white maxw(white x,white y){ if(x.x==-1&&x.y==-1)return y; if(y.x==-1&&y.y==-1)return x; if(x.x==-1||x.y==-1)return y; if(y.x==-1||y.y==-1)return x; if(calcw(x)>calcw(y))return x;else return y; } black maxb(black x,black y){ if(x.x==-1&&x.y==-1)return y; if(y.x==-1&&y.y==-1)return x; if(x.x==-1||x.y==-1)return y; if(y.x==-1||y.y==-1)return x; if(calcb(x)>calcb(y))return x;else return y; } inline white operator +(const white x,const white y){ return maxw(maxw(x,y),maxw(maxw(maxw((white){x.x,y.x},(white){x.x,y.y}),(white){x.y,y.x}),(white){x.y,y.y})); } inline black operator +(const black x,const black y){ return maxb(maxb(x,y),maxb(maxb(maxb((black){x.x,y.x},(black){x.x,y.y}),(black){x.y,y.x}),(black){x.y,y.y})); } inline ll Calc(const black x,const white y){ return max(max(max(calc(x.x,y.x),calc(x.x,y.y)),calc(x.y,y.x)),calc(x.y,y.y)); } pair<black,white>DP(int x,ll val){ pair<black,white>ret={{-1,-1},{-1,-1}}; if(col[x]==1)ret.first.x=x; if(col[x]==2)ret.second.x=x; for(rt i=xs.F[x];i;i=xs.N[i]){ pair<black,white>la=DP(xs.a[i],val); ll res=max(Calc(ret.first,la.second),Calc(la.first,ret.second))+val-2ll*T2.deep[x]; ans=max(ans,res); ret.first=ret.first+la.first; ret.second=ret.second+la.second; } return ret; } void solve(int x,int siz){ if(siz==1)return; nowmin=all=siz; get(x,x); int xx=T1.a[ed],yy=T1.a[ed^1];vis[ed>>1]=1;int now=sz[xx]; sum=0;printblack(xx,yy);printwhite(yy,xx);B=xx;W=yy; build(sum,A);DP(Root,T1.c[ed]); solve(xx,now);solve(yy,siz-now); } int main(){ n=read();la=n; for(rt i=1;i<n;i++){ x=read();y=read();ll z=read(); T1.add(x,y,z); T1.add(y,x,z); } for(rt i=1;i<n;i++){ x=read();y=read();ll z=read(); T2.add(x,y,z); T2.add(y,x,z); } for(rt i=1;i<n;i++){ x=read();y=read();ll z=read(); T3.add(x,y,z); T3.add(y,x,z); } T1.rebuild_init(1,1);T1.rebuild(); T1.dfs(1,1);T1.LCA_init();T2.dfs(1,1);T2.LCA_init();T3.dfs(1,1);T3.LCA_init(); solve(1,n); cout<<ans; return 0; }