【CTSC2018】暴力寫掛(邊分治,虛樹)
阿新 • • 發佈:2018-12-29
【CTSC2018】暴力寫掛(邊分治,虛樹)
題面
題解
發現第二棵樹上的\(LCA\)的深度這玩意沒法搞,那麼列舉在第二棵樹上的\(LCA\)。
然後剩下的部分就是\(dep[x]+dep[y]-dep[lca]\)
這個玩意亂搞一下,就是\(\frac{1}{2}(dep[x]+dep[y]+dis(x,y))\)。
這樣子就和\(LCA\)沒有關係啦。
對於第一棵樹進行邊分治,分治兩側丟到第二棵樹上建虛樹做一遍樹形\(dp\)求最大值就完事了???
然後常數巨大,最後換了一種方式寫虛樹,常數就小了很多(兩遍\(sort\)太慢了),不過似乎可以把\(sort\)
然後就卡過去了QwQ(其實只跑了3s)。
(程式碼裡面註釋的部分就是我原來寫的虛樹,,,,常數有點小大)
#include<iostream> #include<cstdio> #include<cstdlib> #include<cstring> #include<cmath> #include<algorithm> #include<vector> using namespace std; #define ll long long #define MAX 400400 inline int read() { int x=0;bool t=false;char ch=getchar(); while((ch<'0'||ch>'9')&&ch!='-')ch=getchar(); if(ch=='-')t=true,ch=getchar(); while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar(); return t?-x:x; } int n; int S[2][MAX],top[2],type[MAX]; int lg[MAX<<1]; ll W[MAX],ans=-1e18; namespace Tree2 { struct Line{int v,next;ll w;}e[MAX<<1]; int h[MAX],cnt=1; inline void Add(int u,int v,ll w){e[cnt]=(Line){v,h[u],w};h[u]=cnt++;} int dep[MAX];ll dis[MAX]; int dfn[MAX],low[MAX],tim; int st[20][MAX<<1],sum,fir[MAX]; void dfs(int u,int ff) { dfn[u]=++tim;dep[u]=dep[ff]+1;st[0][++sum]=u;fir[u]=sum; for(int i=h[u];i;i=e[i].next) if(e[i].v!=ff) dis[e[i].v]=dis[u]+e[i].w,dfs(e[i].v,u),st[0][++sum]=u; low[u]=tim; } int compare(int a,int b){return dep[a]<dep[b]?a:b;} void pre() { for(int j=1;j<=lg[sum];++j) for(int i=1;i+(1<<j)-1<=sum;++i) st[j][i]=compare(st[j-1][i],st[j-1][i+(1<<(j-1))]); memset(h,0,sizeof(h)); } int LCA(int u,int v) { u=fir[u],v=fir[v];if(u>v)swap(u,v); int k=lg[v-u+1]; return compare(st[k][u],st[k][v-(1<<k)+1]); } bool cmp(int a,int b){return dfn[a]<dfn[b];} int Q[MAX<<1],T,Stack[MAX];bool vis[MAX]; ll f[MAX][2]; bool book[MAX]; void DP(int u,ll Pls) { f[u][0]=f[u][1]=-1e18;if(vis[u])f[u][type[u]]=W[u]; for(int i=h[u];i;i=e[i].next) { int v=e[i].v;DP(v,Pls); ans=max(ans,Pls+max(f[u][0]+f[v][1],f[u][1]+f[v][0])-2*dis[u]); f[u][0]=max(f[u][0],f[v][0]); f[u][1]=max(f[u][1],f[v][1]); } h[u]=0;vis[u]=false; } void Solve(ll Pls) { cnt=1;T=0; for(int i=1;i<=top[0];++i)Q[++T]=S[0][i]; for(int i=1;i<=top[1];++i)Q[++T]=S[1][i]; for(int i=1;i<=T;++i)vis[Q[i]]=true; sort(&Q[1],&Q[T+1],cmp); int top=0;if(Q[1]!=1)Stack[++top]=1; for(int i=1;i<=T;++i) { int u=Q[i],ff=LCA(u,Stack[top]); while(top>1&&dep[Stack[top-1]]>=dep[ff])Add(Stack[top-1],Stack[top],0),--top; if(ff!=Stack[top])Add(ff,Stack[top],0),Stack[top]=ff; Stack[++top]=u; } while(top>1)Add(Stack[top-1],Stack[top],0),--top; /* for(int i=T,p;i>1;--i) { p=LCA(Q[i],Q[i-1]);if(book[p])continue; book[p]=true;Q[++T]=p; } sort(&Q[1],&Q[T+1],cmp); for(int i=1,top=0;i<=T;++i) { while(top&&low[Stack[top]]<dfn[Q[i]])--top; if(top)Add(Stack[top],Q[i],dis[Q[i]]-dis[Stack[top]]); Stack[++top]=Q[i]; } */ DP(1,Pls); } } namespace Tree1 { struct Line{int v,next,w;}e[MAX<<3]; int h[MAX<<2],cnt=1,V[MAX<<2]; inline void Add(int u,int v,int w){e[cnt]=(Line){v,h[u],w};h[u]=cnt++;} vector<int> son[MAX<<2]; int N,size[MAX<<2];ll dis[MAX<<2],dep[MAX<<2]; void dfs(int u,int ff) { for(int i=h[u];i;i=e[i].next) if(e[i].v!=ff) son[u].push_back(e[i].v),dep[e[i].v]=dep[u]+e[i].w,V[e[i].v]=e[i].w,dfs(e[i].v,u); } void ReBuild() { memset(h,0,sizeof(h));cnt=2; for(int i=1;i<=N;++i) { int l=son[i].size(); if(l<=2) for(int j=0;j<l;++j) Add(i,son[i][j],V[son[i][j]]),Add(son[i][j],i,V[son[i][j]]); else { int ls=++N,rs=++N; Add(i,ls,0);Add(ls,i,0);Add(i,rs,0);Add(rs,i,0); for(int j=0;j<l;++j) if(j&1)son[ls].push_back(son[i][j]); else son[rs].push_back(son[i][j]); } } } int rt,mx; bool vis[MAX<<2]; void getroot(int u,int ff,int Size) { size[u]=1; for(int i=h[u];i;i=e[i].next) { int v=e[i].v;if(v==ff||vis[i>>1])continue; getroot(v,u,Size);size[u]+=size[v]; int ret=max(size[v],Size-size[v]); if(ret<mx)mx=ret,rt=i; } } void dfs(int u,int ff,int opt) { z if(u<=n)S[opt][++top[opt]]=u,type[u]=opt; for(int i=h[u];i;i=e[i].next) if(e[i].v!=ff&&!vis[i>>1]) dis[e[i].v]=dis[u]+e[i].w,dfs(e[i].v,u,opt); } void Divide(int u,int Size) { mx=1e9;getroot(u,0,Size); if(mx>=1e9)return;vis[rt>>1]=true; int nw=rt,SS=Size-size[e[rt].v]; top[0]=top[1]=dis[e[rt].v]=dis[e[rt^1].v]=0; dfs(e[rt].v,0,0);dfs(e[rt^1].v,0,1); if(!top[0]&&!top[1])return; for(int i=1;i<=top[0];++i)W[S[0][i]]+=dis[S[0][i]]+dep[S[0][i]]; for(int i=1;i<=top[1];++i)W[S[1][i]]+=dis[S[1][i]]+dep[S[1][i]]; Tree2::Solve(e[rt].w); for(int i=1;i<=top[0];++i)W[S[0][i]]-=dis[S[0][i]]+dep[S[0][i]]; for(int i=1;i<=top[1];++i)W[S[1][i]]-=dis[S[1][i]]+dep[S[1][i]]; Divide(e[nw].v,size[e[nw].v]); Divide(e[nw^1].v,SS); } } int main() { n=read();Tree1::N=n; for(int i=2;i<=n+n;++i)lg[i]=lg[i>>1]+1; for(int i=1;i<n;++i) { int u=read(),v=read(),w=read(); Tree1::Add(u,v,w);Tree1::Add(v,u,w); } for(int i=1;i<n;++i) { int u=read(),v=read(),w=read(); Tree2::Add(u,v,w);Tree2::Add(v,u,w); } Tree1::dfs(1,0);Tree1::ReBuild(); Tree2::dfs(1,0);Tree2::pre(); Tree1::Divide(1,Tree1::N); ans/=2; for(int i=1;i<=n;++i)ans=max(ans,Tree1::dep[i]-Tree2::dis[i]); printf("%lld\n",ans); return 0; }