WC2018通道

题意:给你三棵树,求两个点,使得他们在三棵树上的距离和最大,输出最大距离

显然第1,2棵树分别为边分治,虚树,第3棵不会啊QWQ

\[d_1[i]+d_2[i]+d_1[j]+d_2[j]-2*d_2[lca] \]

枚举\(lca\),答案就与最后一项无关了,加上第3可树

\[ans=d_1[i]+d_2[i]+d_1[j]+d_2[j]+dis_3(i,j) \]

第3棵树,每个点新建一个\(i`\)\(i\)\(d_1[i]+d_2[i]\)的边权,于是求满足分别是集合\(L/R\)内的点的最长路径

最长路径的点只可能是L,R,分别的直径的两点

于是虚树上DP

\(f[i][0/1],i\)子树内染色为0/1的点集的最远点对

合并前拿\(f[x][0],f[v][1]\)\(f[x][1],f[v][0]\)更新答案即可,注意加上之前边分时作为重心的边,减去第二棵树上枚举的lca即x的距离*2

调题部分:

pre_e和e的混用
虚树DP后的清零节点
虚树建立后起点问题
虚树栈的清零地方,憨憨了

st预处理时若不限制范围,肯会超出序列长度RE

for(int j=1; j<=lg[tim]; j++)
	for(int i=1; i+(1<<(j-1))<=tim; i++)//st表小心爆空间 
		mn[i][j]=gmin(mn[i][j-1],mn[i+(1<<(j-1))][j-1]);
//!!i+(1<<(j-1))<=tim;
//starusc
/*
数据不清空,爆零两行泪。
多测不读完,爆零两行泪。
边界不特判,爆零两行泪。
贪心不证明,爆零两行泪。
D P 顺序错,爆零两行泪。
大小少等号,爆零两行泪。
变量不统一,爆零两行泪。
越界不判断,爆零两行泪。
调试不注释,爆零两行泪。
溢出不 l l,爆零两行泪。
*/
#include<bits/stdc++.h>
using namespace std;
#define int long long
inline int read() {
	int x=0,f=1;
	char c=getchar();
	while(!isdigit(c)) {
		if(c=='-')f=-1;
		c=getchar();
	}
	while(isdigit(c)) {
		x=(x<<1)+(x<<3)+(c^48);
		c=getchar();
	}
	return f==1?x:-x;
}
const int N=1e5+4;
int n,ans,extra_w,d1[N<<1],d2[N],d3[N],col[N];
vector<int>key;
namespace t3 {
	struct edge {
		int v,w,nxt;
	} e[N<<1];
	int first[N],cnt;
	inline void add(int u,int v,int w) {
		e[++cnt].v=v;
		e[cnt].w=w;
		e[cnt].nxt=first[u];
		first[u]=cnt;
	}
	int tim,dep[N],dfn[N],st[N<<1],idx[N<<1],mn[N<<1][20],lg[N<<1];
	void dfs_1(int x,int fa) {
		dep[x]=dep[fa]+1;
		dfn[x]=++tim;
		st[tim]=dep[x];
		idx[tim]=x;
		for(int i=first[x],v; i; i=e[i].nxt) {
			v=e[i].v;
			if(v==fa)continue;
			d3[v]=d3[x]+e[i].w;
			dfs_1(v,x);
			st[++tim]=dep[x];
			idx[tim]=x;
		}
	}
	inline int gmin(int x,int y) {
		return st[x]<st[y]?x:y;
	}
	inline int findlca(int x,int y) {
		x=dfn[x];
		y=dfn[y];
		if(x>y)x^=y^=x^=y;
		int k=lg[y-x+1];
		return idx[gmin(mn[x][k],mn[y-(1<<k)+1][k])];
	}
	inline int dis(int x,int y) {
		if(!x||!y)return -1;
		return d1[x]+d2[x]+d3[x]+d1[y]+d2[y]+d3[y]-d3[findlca(x,y)]*2;
	}
	inline void build() {
		for(int i=1,u,v,w; i<n; i++) {
			u=read();
			v=read();
			w=read();
			add(u,v,w);
			add(v,u,w);
		}
		dfs_1(1,0);
		for(int i=2; i<=tim; i++)lg[i]=lg[i>>1]+1;
		for(int i=1; i<=tim; i++)mn[i][0]=i;
		for(int j=1; j<=lg[tim]; j++)
			for(int i=1; i+(1<<(j-1))<=tim; i++)//st表小心爆空间 
				mn[i][j]=gmin(mn[i][j-1],mn[i+(1<<(j-1))][j-1]);
	}
}
namespace t2 {
	struct edge {
		int v,w,nxt;
	} E[N<<1];
	int first[N],cnt;
	inline void add(int u,int v,int w) {
		E[++cnt].v=v;
		E[cnt].w=w;
		E[cnt].nxt=first[u];
		first[u]=cnt;
	}
	int tim,dep[N],dfn[N],st[N<<1],idx[N<<1],mn[N<<1][20],lg[N<<1];
	void dfs_1(int x,int fa) {
		dep[x]=dep[fa]+1;
		dfn[x]=++tim;
		st[tim]=dep[x];
		idx[tim]=x;
		for(int i=first[x],v; i; i=E[i].nxt) {
			v=E[i].v;
			if(v==fa)continue;
			d2[v]=d2[x]+E[i].w;
			dfs_1(v,x);
			st[++tim]=dep[x];
			idx[tim]=x;
		}
	}
	inline int gmin(int x,int y) {
		return st[x]<st[y]?x:y;
	}
	inline int findlca(int x,int y) {
		x=dfn[x];
		y=dfn[y];
		if(x>y)x^=y^=x^=y;
		int k=lg[y-x+1];
		return idx[gmin(mn[x][k],mn[y-(1<<k)+1][k])];
	}
	inline void build() {
		for(int i=1,u,v,w; i<n; i++) {
			u=read();
			v=read();
			w=read();
			add(u,v,w);
			add(v,u,w);
		}
		dfs_1(1,0);
		for(int i=2; i<=tim; i++)lg[i]=lg[i>>1]+1;
		for(int i=1; i<=tim; i++)mn[i][0]=i;
		for(int j=1; j<=lg[tim]; j++)
			for(int i=1; i+(1<<(j-1))<=tim; i++)
				mn[i][j]=gmin(mn[i][j-1],mn[i+(1<<(j-1))][j-1]);
	}
	inline bool comp(int x,int y) {
		return dfn[x]<dfn[y];
	}
	int top,sta[N];
	vector<int>e[N],clr;
	inline void insert(int x) {
		if(top<2) {
			sta[++top]=x;
			return;
		}
		int lca=findlca(x,sta[top]);
		if(lca==sta[top]) {
			sta[++top]=x;
			return;
		}
		while(top>1&&dfn[sta[top-1]]>=dfn[lca]) {
			e[sta[top-1]].push_back(sta[top]);
			top--;
		}
		if(sta[top]!=lca) {
			e[lca].push_back(sta[top]);
			sta[top]=lca;
		}
		sta[++top]=x;
	}
	struct poin {
		int x,y;
		poin(int xx=0,int yy=0):x(xx),y(yy) {}
	} f[N][2];
	inline poin operator *(const poin &a,const poin &b) {
		static int tmp,tmp2;
		static poin ret;
		ret=a;
		tmp=t3::dis(a.x,a.y);
		tmp2=t3::dis(b.x,b.y);
		if(tmp2>tmp) {
			tmp=tmp2;
			ret=poin(b.x,b.y);
		}
		tmp2=t3::dis(a.x,b.x);
		if(tmp2>tmp) {
			tmp=tmp2;
			ret=poin(a.x,b.x);
		}
		tmp2=t3::dis(a.x,b.y);
		if(tmp2>tmp) {
			tmp=tmp2;
			ret=poin(a.x,b.y);
		}
		tmp2=t3::dis(b.x,a.y);
		if(tmp2>tmp) {
			tmp=tmp2;
			ret=poin(b.x,a.y);
		}
		tmp2=t3::dis(a.y,b.y);
		if(tmp2>tmp) {
			tmp=tmp2;
			ret=poin(a.y,b.y);
		}
		return ret;
	}
	inline int calc(const poin &a,const poin &b) {
		return max(max(t3::dis(a.x,b.x),t3::dis(a.x,b.y)),max(t3::dis(a.y,b.x),t3::dis(a.y,b.y)));
	}
	void dp(int x) {
		clr.push_back(x);
		if(col[x])f[x][col[x]-1]=poin(x,x);
		for(auto v:e[x]) {
			dp(v);
			ans=max(ans,calc(f[x][0],f[v][1])-d2[x]*2+extra_w);
			ans=max(ans,calc(f[x][1],f[v][0])-d2[x]*2+extra_w);
			f[x][0]=f[x][0]*f[v][0];
			f[x][1]=f[x][1]*f[v][1];
		}
	}
	inline void solve() {
		if(key.empty())return;
		sort(key.begin(),key.end(),comp);
		top=0;//!
		for(auto v:key)insert(v);
		while(top>1) {
			e[sta[top-1]].push_back(sta[top]);
			top--;
		}
		dp(sta[1]);//
		for(auto v:clr) {
			f[v][0]=f[v][1]=poin(0,0);
			e[v].clear();
			d1[v]=0;
		}
		key.clear();
		clr.clear();
	}
}
namespace t1 {
	struct edge {
		int v,w,nxt;
	} e[N<<2],pre_e[N<<1];
	int first[N<<1],pre_fir[N],cnt=1,pre_cnt;
	inline void add(int u,int v,int w) {
		e[++cnt].v=v;
		e[cnt].w=w;
		e[cnt].nxt=first[u];
		first[u]=cnt;
	}
	inline void pre_add(int u,int v,int w) {
		pre_e[++pre_cnt].v=v;
		pre_e[pre_cnt].w=w;
		pre_e[pre_cnt].nxt=pre_fir[u];
		pre_fir[u]=pre_cnt;
	}
	int tot,sum,rt,rt_min,vis[N<<2],siz[N<<1];
	void rebuild(int x,int fa) {
		for(int i=pre_fir[x],nw=0,v; i; i=pre_e[i].nxt) {
			v=pre_e[i].v;
			if(v==fa)continue;
			if(!nw) {
				add(x,v,pre_e[i].w);
				add(v,x,pre_e[i].w);
				nw=x;
			} else {
				add(nw,++tot,0);
				add(tot,nw,0);
				nw=tot;
				add(nw,v,pre_e[i].w);
				add(v,nw,pre_e[i].w);
			}
			rebuild(v,x);
		}
	}
	inline void build() {
		for(int i=1,u,v,w; i<n; i++) {
			u=read();
			v=read();
			w=read();
			pre_add(u,v,w);
			pre_add(v,u,w);
		}
		tot=n;
		rebuild(1,0);
		sum=tot;
	}
	void findrt(int x,int fa) {
		siz[x]=1;
		for(int i=first[x],v; i; i=e[i].nxt) {
			v=e[i].v;
			if(v==fa||vis[i])continue;
			findrt(v,x);
			siz[x]+=siz[v];
			if(!rt||vis[rt]||max(siz[v],sum-siz[v])<rt_min) {
				rt_min=max(siz[v],sum-siz[v]);
				rt=i;
			}
		}
	}
	void getdis(int x,int fa,int c) {
		siz[x]=1;
		if(x<=n) {
			col[x]=c;
			key.push_back(x);
		}
		for(int i=first[x],v; i; i=e[i].nxt) {
			v=e[i].v;
			if(v==fa||vis[i])continue;
			d1[v]=d1[x]+e[i].w;
			getdis(v,x,c);
			siz[x]+=siz[v];
		}
	}
	void solve(int x) {
		if(sum==1)return;
		findrt(x,0);
		int gr=e[rt].v,gl=e[rt^1].v;
		vis[rt]=vis[rt^1]=1;
		d1[gl]=d1[gr]=0;
		extra_w=e[rt].w;
		getdis(gl,0,1);
		getdis(gr,0,2);
		t2::solve();
		sum=siz[gl];
		solve(gl);
		sum=siz[gr];
		solve(gr);
	}
}
signed main() {
	n=read();
	t1::build();
	t2::build();
	t3::build();
	t1::solve(1);
	cout<<ans;
	return (0-0);
}
//pre_e和e的混用
//虚树DP后的清零节点
//虚树建立后起点问题
//虚树栈的清零地方,憨憨了

猜你喜欢

转载自www.cnblogs.com/aurora2004/p/12985613.html