1. 程式人生 > >LOJ#2339. 「WC2018」通道(邊分治+虛樹)

LOJ#2339. 「WC2018」通道(邊分治+虛樹)

傳送門

題解: 考慮兩棵樹怎麼做,要求maxd1(x)+d1(y)2lca1(x,y)+dis2(x,y)\max d_1(x)+d_1(y)-2*lca_1(x,y)+dis_2(x,y),把xx'掛在xx下面,長度為d1(x)d_1(x),然後就是max2lca1(x,y)+dis2(x,y)\max -2*lca_1(x,y)+dis_2(x,y)

相當於對於第一棵樹求在第二棵樹裡面的直徑。 因為沒有負邊權,我們直接記錄最長鏈即可。

第三棵樹採用邊分治,對於每一層,相當於求max2lca1(x,y)+dis2(x,y)+d3(x)+d3(y)\max -2*lca_1(x,y)+dis_2(x,y)+d_3(x)+d_3(y)。 用類似的方法,接在下方,然後相當於是第一棵樹的每棵子樹求一下兩類點(邊分治的兩邊)的直徑。 AABB集合的直徑一定在AA集合最長鏈,BB集合最長鏈的兩端取得(在沒有負權的情況下)。 然後就是一樣的做法了。

用歸併排序建虛樹,O(1)O(1)lca,可以做到O(nlogn)O(n \log n)

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef pair <int,LL> pii;

const int RLEN=1<<18|1;
inline char nc() {
	static char ibuf[RLEN],*ib,*ob;
	(ib==ob) && (ob=(ib=ibuf)+fread(ibuf,1,RLEN,stdin));
	return (ib==ob) ? -1 : *ib++;
}
inline
LL rd() { char ch=nc(); LL i=0,f=1; while(!isdigit(ch)) {if(ch=='-')f=-1; ch=nc();} while(isdigit(ch)) {i=(i<<1)+(i<<3)+ch-'0'; ch=nc();} return i*f; } const int N=2e5+50, L=18; int n,lg[N]; LL ans; struct chain { int x,y; LL l; chain(int x=0,int y=0,LL l=0) : x(x),y(y),l(l) {} friend inline bool operator <(const chain &a,const chain &b) {return a.l<b.l || (a.l==b.l && a.x<b.x);} }; struct T1 { int dfn[N],sze[N],pos[N],st[N][L+1],id[N]; LL dep[N]; vector <pii> e[N]; int tot,ind; inline void dfs(int x,int f) { id[dfn[x]=++ind]=x; sze[x]=1; st[pos[x]=++tot][0]=ind; for(auto v:e[x]) if(v.first^f) { dep[v.first]=dep[x]+v.second; dfs(v.first,x); st[++tot][0]=dfn[x]; sze[x]+=sze[v.first]; } } inline void init() { for(int i=1;i<n;i++) { int x=rd(), y=rd(); LL w=rd(); e[x].push_back(pii(y,w)); e[y].push_back(pii(x,w)); } dfs(1,0); for(int i=1;i<=lg[tot];i++) for(int j=1;j+(1<<i)-1<=tot;++j) st[j][i]=min(st[j][i-1],st[j+(1<<(i-1))][i-1]); } inline int lca(int x,int y) { if(pos[x]>pos[y]) swap(x,y); int l=lg[pos[y]-pos[x]+1]; return id[min(st[pos[x]][l],st[pos[y]-(1<<l)+1][l])]; } inline bool in(int x,int y) {return dfn[y]<dfn[x]+sze[x] && dfn[y]>dfn[x];} } t1,t2; namespace t3 { int stx,sty,mxv,total; LL stl; int bl[N],sze[N],vs,tot; LL dep[N]; vector <pii> e1[N]; vector <pii> e2[N]; vector <int> e[N]; inline void dfs(int x,int f) { vector <pii> vec; for(auto v:e1[x]) if(v.first^f) vec.push_back(v), dfs(v.first,x); for(int j=0;j<vec.size();++j) { e2[++tot].push_back(vec[j]); e2[vec[j].first].push_back(pii(tot,vec[j].second)); int pre=j ? tot-1 : x; e2[pre].push_back(pii(tot,0)); e2[tot].push_back(pii(pre,0)); } } inline void init() { for(int i=1;i<n;i++) { int x=rd(), y=rd(); LL w=rd(); e1[x].push_back(pii(y,w)); e1[y].push_back(pii(x,w)); } tot=n; dfs(1,0); } inline void calcG(int x,int f) { sze[x]=1; for(auto v:e2[x]) if(v.first^f && bl[v.first]==bl[x]) { calcG(v.first,x); sze[x]+=sze[v.first]; if(max(sze[v.first],total-sze[v.first])<=mxv) { mxv=max(sze[v.first],total-sze[v.first]); stx=x; sty=v.first; stl=v.second; } } bl[x]=vs; } int stk[N],id[N],top,ic; int fa[N],a[N],cnt,rt; chain mx[N][2]; inline void build_vir(vector <int> &q) { cnt=top=0; for(auto i:q) a[++cnt]=i; for(auto i:q) { if(!top) stk[++top]=rt=i; else { int l=t1.lca(i,stk[top]); while(t1.in(l,stk[top])) { if(top==1 || t1.in(stk[top-1],l)) fa[stk[top]]=l; --top; } if(l!=stk[top]) { if(!top) rt=l; a[++cnt]=l; fa[l]=stk[top]; stk[++top]=l; } fa[i]=stk[top]; stk[++top]=i; } } for(int i=1;i<=cnt;i++) e[a[i]].clear(); for(int i=1;i<=cnt;i++) if(a[i]!=rt) e[fa[a[i]]].push_back(a[i]); } inline LL ask_dis(int x,int y) { int l=t2.lca(x,y); return t2.dep[x]+t2.dep[y]-2*t2.dep[l]+t1.dep[x]+dep[x]+t1.dep[y]+dep[y]; } inline void upt_ans(int i,int x,int y) { ans=max(ans,ask_dis(x,y)-2*t1.dep[i]); } inline chain merge(chain &a,chain &b) { chain c=chain(0,0,0); c=max(c,chain(a.x,b.x,ask_dis(a.x,b.x))); c=max(c,chain(a.x,b.y,ask_dis(a.x,b.y))); c=max(c,chain(a.y,b.x,ask_dis(a.y,b.x))); c=max(c,chain(a.y,b.y,ask_dis(a.y,b.y))); return max(a,max(b,c)); } inline void merge(int x,int y) { for(int i=0;i<=1;i++)