WC2018 通道

好久以前开的坑.
到今天才填上.

首先考虑队第一颗树边分,然后分成两个集合(L,R),在第二棵树上建出虚树,在每个路径(lca)处统计答案,维护点集的直径只有正权很好维护.

#include <bits/stdc++.h>

using namespace std;
typedef long long ll;
typedef pair<int,int> p;
typedef pair<p,p> pp;
struct edge{
	int x;
	ll w;
	bool operator ==(const edge &_) const{
		return x==_.x&&w==_.w;
	}
	void print(){
		cerr<<"{"<<x<<","<<w<<"} ";
	}
};
typedef vector<edge> vi;
typedef vector<vector<edge> > vvi;
vi operator +(const vi &a,const vi &b){
	vi ret(a);
	ret.insert(ret.end(),b.begin(),b.end());
	return ret;
}
ostream& operator <<(ostream &ou,const p &a){
	return ou<<"["<<a.first<<","<<a.second<<"]";
}
const int N=100010;
int n;
namespace Tree3{
	vvi TG;
	int dep[N],top[N],fa[N],sz[N],son[N];
	ll dis[N];
	int getlca(int x,int y){
		while (top[x]!=top[y]){
			if (dep[top[x]]>dep[top[y]]) swap(x,y);
			y=fa[top[y]];
		}
		return dep[x]<dep[y]?x:y;
	}
	ll getdis(int x,int y){
		return dis[x]+dis[y]-2*dis[getlca(x,y)];
	}
	void Dfs(int x,int f=0){
		fa[x]=f;
		dep[x]=dep[f]+1;
		sz[x]=1;
		for (auto i:TG[x])
			if (i.x!=f){
				dis[i.x]=dis[x]+i.w;
				Dfs(i.x,x);
				sz[x]+=sz[i.x];
				if (sz[i.x]>sz[son[x]]) son[x]=i.x;
			}
	}
	void Sfd(int x,int tp,int f=0){
		top[x]=tp;
		if (son[x]) Sfd(son[x],tp,x);
		for (auto i:TG[x])
			if (i.x!=f&&i.x!=son[x]) Sfd(i.x,i.x,x);
	}
	void read(){
		TG.resize(n+1);
		for (int i=1; i<n; ++i){
			int x,y;
			ll w;
			scanf("%d%d%lld",&x,&y,&w);
			TG[x].push_back({y,w});
			TG[y].push_back({x,w});
		}
		Dfs(1);
		Sfd(1,1);
	}
}
namespace Tree2{
	const ll INF=1e18;
	vvi TG;
	int dep[N],col[N],clk,dfn[N],fa[N][17],dtime;
	ll dis[N],cost[N],ret;
	pp diameter[N];
	vector<int> E[N];
	int getlca(int x,int y){
		if (dep[x]>dep[y]) swap(x,y);
		for (int i=16; i>=0; --i) if (dep[fa[y][i]]>=dep[x]) y=fa[y][i];
		if (x==y) return x;
		for (int i=16; i>=0; --i) if (fa[y][i]!=fa[x][i]) x=fa[x][i],y=fa[y][i];
		return fa[x][0];
	}
	void Dfs(int x,int f=0){
		fa[x][0]=f;
		for (int i=1; i<17; ++i) fa[x][i]=fa[fa[x][i-1]][i-1];
		dfn[x]=++clk;
		dep[x]=dep[f]+1;
		for (auto i:TG[x])
			if (i.x!=f){
				dis[i.x]=dis[x]+i.w;
				Dfs(i.x,x);
			}
	}
	void read(){
		//cerr<<"readbegin2"<<endl;
		TG.resize(n+1);
		for (int i=1; i<n; ++i){
			int u,v;
			ll w;
			scanf("%d%d%lld",&u,&v,&w);
			TG[u].push_back({v,w});
			TG[v].push_back({u,w});
		}
		Dfs(1);
		//cerr<<"readend2"<<endl;
	}
	bool cmp(const edge &a,const edge &b){
		return dfn[a.x]<dfn[b.x];
	}
	ll calc(int a,int b){
		if (!(a&&b)) return (a||b)?-INF:-2*INF;
		if (a==b) return 0;
		//cerr<<"calc"<<a<<" "<<b<<" "<<cost[a]+cost[b]+dis[a]+dis[b]+Tree3::getdis(a,b)<<" "<<dis[a]+dis[b]<<endl;
		return cost[a]+cost[b]+dis[a]+dis[b]+Tree3::getdis(a,b);
	}
	ll calc(const p &a,const p &b){
		return max(max(calc(a.first,b.second),calc(a.first,b.first)),max(calc(a.second,b.first),calc(a.second,b.second)));
	}
	p operator +(const p &a,int b){
		ll t=calc(a.first,a.second);
		ll t2=calc(a.first,b);
		ll t3=calc(a.second,b);
		return max(t2,t3)>t?p({t2>=t3?a.first:a.second,b}):a;
	}
	p operator +(const p &a,const p &b){
		return (a+b.first)+b.second;
	}
	pp operator +(const pp &a,const pp &b){
		return {a.first+b.first,a.second+b.second};
	}
	p tr(int x){
		return {x,x};
	}
	int tim,vis[N],faf[N];
	void dfs(int x){
		//cerr<<"dfs on virtual tree:"<<x<<" "<<dis[x]<<endl;
		diameter[x]={tr(col[x]&1?x:0),tr(col[x]&1?0:x)};
		//cerr<<diameter[x].first<<" "<<diameter[x].second<<" "<<ret<<endl;
		for (auto i:E[x]){
			dfs(i);
			ret=max(ret,calc(diameter[x].first,diameter[i].second)-dis[x]*2);
			ret=max(ret,calc(diameter[x].second,diameter[i].first)-dis[x]*2);
			//cerr<<"aftmerge"<<x<<" "<<i<<" "<<diameter[x].first<<" "<<diameter[x].second<<" "<<ret<<" "<<dis[x]<<endl;
			diameter[x]=diameter[x]+diameter[i];
			
		}
		faf[x]=0;
		E[x].clear();
		//cerr<<"endi"<<x<<" "<<diameter[x].first<<" "<<diameter[x].second<<" "<<ret<<endl;
	}
	ll build_virtual_tree(vi a){
		sort(a.begin(),a.end(),cmp);
		stack<int> s;
		int rt=a[0].x;
		ret=0;
		vector<int> vim;
		for (auto i:a){
			vim.push_back(i.x);
			if (s.size()){
				int lca=getlca(s.top(),i.x);
				vim.push_back(lca);
				//cerr<<"build"<<i.x<<" "<<lca<<" "<<faf[1]<<endl;
				if (dep[lca]<dep[rt]) rt=lca;
				while (dep[faf[s.top()]]>dep[lca]) s.pop();
				bool cd=(faf[s.top()]!=lca);
				if (cd) faf[lca]=faf[s.top()];
				if (s.top()!=lca) faf[s.top()]=lca;
				s.pop();
				if (cd) s.push(lca);
				faf[i.x]=lca;
			}
			s.push(i.x);
		}
		++tim;
		for (auto i:vim)
			if (vis[i]<tim){
				vis[i]=tim;
				//cerr<<"fa"<<i<<" "<<faf[i]<<endl;
				E[faf[i]].push_back(i);
			}
		//cerr<<"ESZE"<<E[rt].size()<<" "<<rt<<endl;
		//exit(0);
		dfs(rt);
		return ret;
	}
	ll main(vi &u,vi &v){
		if (!(u.size()&&v.size())) return -INF;
		++dtime;
		for (auto i:u){
			col[i.x]=dtime;
			cost[i.x]=i.w;
		}
		++dtime;
		for (auto i:v){
			col[i.x]=dtime;
			cost[i.x]=i.w;
		}
		return build_virtual_tree(u+v);
	}
}
namespace Tree1{
	vvi G,TG;
	int sz[N<<1];
	int aa,bb,cnt,val;
	ll ans,ww;
	void dfs(int x,int f){
		for (auto i:TG[x])
			if (i.x!=f) dfs(i.x,x);
		int now=x;
		for (auto i:TG[x])
			if (i.x!=f){
				G[now].push_back({i.x,i.w});
				G[i.x].push_back({now,i.w});
				//cerr<<"cdr"<<now<<" "<<i.x<<" "<<i.w<<endl;
				++cnt;
				G[now].push_back({cnt,0});
				G[cnt].push_back({now,0});
				//cerr<<"car"<<now<<" "<<cnt<<" "<<0<<endl;
				now=cnt;
			}
	}
	void getsz(int x,int f=0){
		sz[x]=1;
		for (auto i:G[x])
			if (i.x!=f){
				getsz(i.x,x);
				sz[x]+=sz[i.x];
			}
	}
	void dfs(int x,int f,ll len){
		if (max(val-sz[x],sz[x])<max(val-sz[aa],sz[aa])){
			aa=x;
			bb=f;
			ww=len;
		}
		for (auto i:G[x])
			if (i.x!=f) dfs(i.x,x,i.w);
	}
	void Getpoint(int x,vi &g,int f=0,ll dis=0){
		if (x<=n) g.push_back({x,dis});
		for (auto i:G[x]) if (i.x!=f) Getpoint(i.x,g,x,dis+i.w);
	}
	void BF(int x){
		//cerr<<"BF"<<x<<endl;
		getsz(x);
		//cerr<<"getend"<<endl;
		aa=x;
		bb=0;
		val=sz[x];
		if (val==1) return;
		//cerr<<"dfsbegin"<<endl;
		dfs(x,0,0);
		//cerr<<"dfsend"<<aa<<" "<<bb<<" "<<ww<<" "<<(find(G[aa].begin(),G[aa].end(),edge{bb,ww})==G[aa].end())<<endl;
		G[aa].erase(find(G[aa].begin(),G[aa].end(),edge{bb,ww}));
		G[bb].erase(find(G[bb].begin(),G[bb].end(),edge{aa,ww}));
		//cerr<<"???"<<endl;
		vi u,v;
		Getpoint(aa,u);
		Getpoint(bb,v);
		//cerr<<"U:"<<endl;
		//for (auto i:u) i.print();
		//cerr<<endl<<"V:"<<endl;
		//for (auto i:v) i.print();
		//cerr<<endl<<"What's the edge:"<<aa<<" "<<bb<<" "<<ww<<endl;
		ans=max(ans,Tree2::main(u,v)+ww);
		//cerr<<"inthisans:"<<ans<<endl;
		//exit(0);
		int tmp=bb;
		BF(aa);
		BF(tmp);
	}
	void main(){
		scanf("%d",&n);
		TG.resize(n+1);
		G.resize(2*n);
		cnt=n;
		for (int i=1; i<n; ++i){
			int u,v;
			ll w;
			scanf("%d%d%lld",&u,&v,&w);
			TG[u].push_back({v,w});
			TG[v].push_back({u,w});
		}
		Tree2::read();
		Tree3::read();


		/*for (int i=1; i<=n; ++i)
			for (int j=1; j<=n; ++j)
			cerr<<i<<" "<<j<<" "<<Tree3::getdis(i,j)<<endl;*/
		dfs(1,0);
		BF(1);
		cout<<ans;
	}
}
int main(){
	Tree1::main();
}
原文地址:https://www.cnblogs.com/Yuhuger/p/10575258.html