洛谷P4220 [WC2018]通道

题面:https://www.luogu.com.cn/problem/P4220
题意:给出三棵树,求出\(dis1(x,y)+dis2(x,y)+dis3(x,y)\)最大值。
题解:
首先,列举一下和深度、距离相关的可能用到的算法:
树剖,\(dis_x\)+\(dis_y\)-2\(dis_{lca(x,y)}\),虚树,点分治,边分治......
先考虑一个O(\(n^2\)logn)的算法:对三棵树树剖,枚举\(i\),\(j\),
\(dis_x\)+\(dis_y\)-2
\(dis_{lca(x,y)}\)求出答案。
这个算法用st表求lca可以做到O(\(n^2\))。
考虑优化这个算法。
肯定不能直接枚举\(i\),\(j\)了,考虑采用分治算法。
先考虑淀粉质。由于一个节点有多个子树,合并子树就显得十分麻烦,
而且还不能简单地采用容斥来排除子树内的贡献。
所以考虑对第一棵树进行边分治。
确定了分界边后,第一棵树的两点间距离可以直接通过一遍DFS处理出来。
设这条边为\((x,y)\),我们把两边的点分别染成黑白两色,设黑为\(B\),白为\(W\)
那么当前要处理的就是\(max(dis(x,i)+dis(x,y)+dis(y,j)+dis2(i,j)+dis3(i,j))\),i\(\in\){\(B\)},j\(\in\){\(W\)}。
\(dis(x,y)\)是个常量,可以扔到一边。再将dis2和dis3化为我们能求出的形式,即:
\(max(dis(x,i)+dis(y,j)+dis2(1,i)+dis2(1,j)-2dis2(1,lca(i,j))+dis3(1,i)+dis3(1,j)-2dis3(1,lca(i,j))\)
\(val[i]\)= \(dis1(x/y,i)+dis2(1,i)+dis3(1,i)\)(这里认为\(dis1[x]\)=\(dis1[y]\)=0),
那么要求的就是最大化\(val[i]+val[j]-2dis2(1,lca(i,j))-2dis3(1,lca(i,j))\)
由于要在点集时间内解决问题,不难想到在第二棵树上建虚树跑DP。
由于可以枚举lca,现在只有\(dis3(1,lca(i,j))\)这一个变量了。
这里有一个lemma:设点集\(S\)的最远点对为\(s1\),\(s2\),\(T\)的最远点对为\(t1\),\(t2\),
那么\(S->T\)的最远点对只可能是(\(s1,t1\)),(\(s1,t2\)),(\(s2,t1\)),(\(s2,t2\))中的一个。
这就提醒我们可以分别记录子树内黑白点的最远点对。这样,就可以用DP解决问题了。
最后,具体实现上有几个小细节:
1.最好用st表求lca,避免再多一个log;
2.多开struct,开三个namespace,以防止变量重名;
3.码量巨大,出问题最好手膜一组小数据试一试。
时间复杂度:O(n\(log^2\)n)
代码:

#include<bits/stdc++.h>
using namespace std;
#define re register ll
#define F(x,y,z) for(re x=y;x<=z;x++)
#define FOR(x,y,z) for(re x=y;x>=z;x--)
typedef long long ll;
#define I inline void
#define IN inline ll
#define C(x,y) memset(x,y,sizeof(x))
#define STS system("pause")
template<class D>I read(D &res){
	res=0;register D g=1;register char ch=getchar();
	while(!isdigit(ch)){
		if(ch=='-')g=-1;
		ch=getchar();
	}
	while(isdigit(ch)){
		res=(res<<3)+(res<<1)+(ch^48);
		ch=getchar();
	}
	res*=g;
}
#define T e[k].to
typedef pair<ll,ll>pil;
ll n,X,Y;ll W,ans,Cent;
ll cnt1,cnt2,q1[404000],q2[404000],clr[404000];
ll val[404000];
namespace T3{
	struct E{
		ll to,nt;ll w;
	}e[202000];
	ll head[101000],tot;
	ll xu[202000],dep[202000],id[202000],lg[202000],f[202000][20];
	ll dis[101000];
	IN getmin(ll x,ll y){
		return dep[x]<dep[y]?x:y;
	}
	I add(ll x,ll y,ll w){
		e[++tot].to=y;e[tot].nt=head[x];head[x]=tot;e[tot].w=w;
	}
	I D_1(ll x,ll fa,ll depth,ll dist){
		dep[x]=depth;xu[++tot]=x;id[x]=tot;dis[x]=dist;val[x]+=dis[x];
		for(re k=head[x];k!=-1;k=e[k].nt){
			if(T==fa)continue;
			D_1(T,x,depth+1,dist+e[k].w);xu[++tot]=x;
		}
	}
	I init(){
		lg[0]=-1;
		F(i,1,tot)f[i][0]=xu[i],lg[i]=lg[i>>1]+1;
		F(j,1,lg[tot]){
			F(i,1,tot-(1<<j)+1)f[i][j]=getmin(f[i][j-1],f[i+(1<<(j-1))][j-1]);
		}
	}
	I build(){
		C(head,-1);tot=-1;
		F(i,1,n-1){
			read(X);read(Y);read(W);
			add(X,Y,W);add(Y,X,W);
		}
		tot=0;
		D_1(1,0,1,0);init();
	}
	IN ques_lca(ll x,ll y){
		x=id[x];y=id[y];
		if(x>y)swap(x,y);
		re len=lg[y-x+1];
		return getmin(f[x][len],f[y-(1<<len)+1][len]);
	}
	IN ques_dis(ll x,ll y){return val[x]+val[y]-(dis[ques_lca(x,y)]<<1);}
};
namespace T2{
	vector<pil>vec[101000];
	struct E{
		ll to,nt;ll w;
	}e[202000];
	ll head[101000],tot;
	ll xu[202000],dep[202000],id[202000],lg[202000],f[202000][20],in[202000],out[202000],dfn;
	ll dis[101000];
	ll top,st[404000];
	ll q[404000],num;
	struct Dat{
		ll x,y;ll dis;
		Dat(){x=y=dis=0;}
		Dat(const ll &_x,const ll &_y){x=_x;y=_y;dis=T3::ques_dis(x,y);}
		Dat(const ll &_x,const ll &_y,const ll &_w){x=_x;y=_y;dis=_w;}
		friend bool operator < (Dat a,Dat b){return a.dis<b.dis;}
		friend Dat operator ^ (Dat a,Dat b){
			if(!a.x)return b;if(!b.x)return a;
			Dat r=max(a,b);
			r=max(r,max(Dat(a.x,b.y),max(Dat(a.y,b.x),max(Dat(a.x,b.x),Dat(a.y,b.y)))));
			return r;
		}
	}dp[202000][2];
	IN getmin(ll x,ll y){
		return dep[x]<dep[y]?x:y;
	}
	I add(ll x,ll y,ll w){
		e[++tot].to=y;e[tot].nt=head[x];head[x]=tot;e[tot].w=w;
	}
	I D_1(ll x,ll fa,ll depth,ll dist){
		dep[x]=depth;xu[++tot]=x;id[x]=tot;dis[x]=dist;val[x]+=dis[x];in[x]=++dfn;
		for(re k=head[x];k!=-1;k=e[k].nt){
			if(T==fa)continue;
			D_1(T,x,depth+1,dist+e[k].w);xu[++tot]=x;
		}
		out[x]=++dfn;
	}
	I init(){
		lg[0]=-1;
		F(i,1,tot)f[i][0]=xu[i],lg[i]=lg[i>>1]+1;
		F(j,1,lg[tot]){
			F(i,1,tot-(1<<j)+1)f[i][j]=getmin(f[i][j-1],f[i+(1<<(j-1))][j-1]);
		}
	}
	I build(){
		C(head,-1);tot=-1;
		F(i,1,n-1){
			read(X);read(Y);read(W);
			add(X,Y,W);add(Y,X,W);
		}
		tot=0;
		D_1(1,0,1,0);init();
	}
	ll oc[404000],lca;
	IN ques_lca(ll x,ll y){
		x=id[x];y=id[y];
		if(x>y)swap(x,y);
		re len=lg[y-x+1];
		return getmin(f[x][len],f[y-(1<<len)+1][len]);
	}
	IN ques(Dat a,Dat b){
		if(!a.x||!b.x)return 0;
		return max(max(T3::ques_dis(a.x,b.x),T3::ques_dis(a.x,b.y)),max(T3::ques_dis(a.y,b.x),T3::ques_dis(a.y,b.y)));
	}
	inline bool bbb(ll x,ll y){
		re k1=(x<0)?out[-x]:in[x],k2=(y<0)?out[-y]:in[y];return k1<k2;
	}
	inline ll Max(ll x,ll y){
		return x>y?x:y;
	}
	I solve(){
		top=0;
		//cout<<endl;
		F(i,1,cnt1)st[++top]=q1[i];
		//cout<<"        ";
		F(i,1,cnt2)st[++top]=q2[i];
		//cout<<endl;
		sort(st+1,st+1+top,bbb);
		F(i,1,top)oc[st[i]]=1;
		//F(i,1,n)cout<<oc[i];
		//cout<<endl;
		F(i,1,top){
			X=st[i];W=clr[X];dp[X][W]=Dat(X,X,0),dp[X][W^1]=Dat();
		}
		tot=top;
		//cout<<"lca:";
		F(i,1,tot-1){
			lca=ques_lca(st[i],st[i+1]);//cout<<lca<<" ";
			if(!oc[lca])oc[lca]=1,st[++top]=lca,dp[lca][0]=dp[lca][1]=Dat();
		}
		//cout<<endl;
		F(i,1,top)oc[st[i]]=0;
		tot=top;
		F(i,1,tot)st[++top]=-st[i];
		sort(st+1,st+1+top,bbb);
		//F(i,1,top)cout<<st[i]<<" ";
		//cout<<endl;
		F(i,1,top){
			if(st[i]>0)q[++num]=st[i];
			else {
				num--;if(!num)continue;
				X=q[num+1],Y=q[num];
				//cout<<X<<" "<<Y<<" "<<dp[X][0].x<<" "<<dp[X][0].y<<" "<<dp[X][1].x<<" "<<dp[X][1].y<<" "<<dp[Y][0].x<<" "<<dp[Y][0].y<<" "<<dp[Y][1].x<<" "<<dp[Y][1].y<<" "<<ques(dp[X][0],dp[Y][1])+Cent-(dis[Y]<<1)<<" "<<ques(dp[X][1],dp[Y][0])+Cent-(dis[Y]<<1)<<" ";
				W=Max(ques(dp[X][0],dp[Y][1]),ques(dp[X][1],dp[Y][0]))+Cent-(dis[Y]<<1);
				ans=Max(ans,W);//cout<<W<<endl;
				dp[Y][0]=dp[Y][0]^dp[X][0];dp[Y][1]=dp[Y][1]^dp[X][1];
			}
		}
	}
};
namespace T1{
	const ll INF=1e9+7;
	vector<pil>vec[101000];
	ll num[101000];
	struct E{
		ll to,nt;ll w;bool v;
	}e[808000];
	ll head[404000],tot,cnt;
	ll siz[404000],V[404000],maxi;
	I add(ll x,ll y,ll w){
		//cout<<"!"<<x<<" "<<y<<endl;
		e[++tot].to=y;e[tot].nt=head[x];head[x]=tot;e[tot].w=w;
	}
	I insert(ll x,pil y){
		++cnt;
		add(cnt,y.first,y.second);add(y.first,cnt,y.second);
		add(num[x],cnt,0);add(cnt,num[x],0);num[x]=cnt;
	}
	I D_1(ll x,ll fa){
		for(auto p:vec[x]){
			if(p.first==fa)continue;
			insert(x,p);
			D_1(p.first,x);
		}
	}
	I build(){
		F(i,1,n-1){
			read(X);read(Y);read(W);
			vec[X].emplace_back(make_pair(Y,W));
			vec[Y].emplace_back(make_pair(X,W));	
		}
		C(head,-1);tot=-1;cnt=n;
		F(i,1,n)num[i]=i;
		D_1(1,0);
	}	
	I D_2(ll x,ll fa){
		siz[x]=1;
		for(re k=head[x];k!=-1;k=e[k].nt){
			if(T==fa||e[k].v)continue;
			D_2(T,x);siz[x]+=siz[T];
		}
	}
	I findroot(ll x,ll fa,ll N){
		for(re k=head[x];k!=-1;k=e[k].nt){
			if(T==fa||e[k].v)continue;
			findroot(T,x,N);
			re now=max(siz[T],N-siz[T]);
			if(now<maxi)maxi=now,W=k;
		}
	}
	I D_3(ll x,ll fa,ll depth){
		V[x]=depth;if(x<=n)q1[++cnt1]=x,clr[x]=0;
		for(re k=head[x];k!=-1;k=e[k].nt){
			if(T==fa||e[k].v)continue;
			D_3(T,x,depth+e[k].w);
		}
	}
	I D_4(ll x,ll fa,ll depth){
		V[x]=depth;if(x<=n)q2[++cnt2]=x,clr[x]=1;
		for(re k=head[x];k!=-1;k=e[k].nt){
			if(T==fa||e[k].v)continue;
			D_4(T,x,depth+e[k].w);
		}
	}
	I D_5(ll x,ll fa){
		for(re k=head[x];k!=-1;k=e[k].nt){
			if(T==fa||e[k].v)continue;
			D_5(T,x);e[k].v=e[k^1].v=1;
		}
	}
	I solve(ll x){
		//cout<<"!"<<x<<" ";
		D_2(x,0);if(siz[x]==1)return;
		maxi=INF;
		findroot(x,0,siz[x]);
		ll A,B,M=W;B=e[M].to,A=e[M^1].to;
		e[M].v=e[M^1].v=1;Cent=e[M].w;
		cnt1=cnt2=0;
		D_3(A,0,0);D_4(B,0,0);
		if(!cnt1||!cnt2){
			if(!cnt1&&!cnt2)return;
			else if(!cnt1)D_5(A,0),solve(B);
			else if(!cnt2)D_5(B,0),solve(A);
			return;
		}
		F(i,1,cnt1)val[q1[i]]+=V[q1[i]];
		F(i,1,cnt2)val[q2[i]]+=V[q2[i]];
		//cout<<A<<" "<<B<<" "<<Cent<<" "<<cnt1<<" "<<cnt2<<":"<<endl;
		T2::solve();
		F(i,1,cnt1)val[q1[i]]-=V[q1[i]];
		F(i,1,cnt2)val[q2[i]]-=V[q2[i]];
		solve(A);solve(B);
	}
};
int main(){
	read(n);
	T1::build();
	T2::build();
	T3::build();
	//F(i,1,n)cout<<val[i]<<" ";
	//cout<<endl;
	T1::solve(1);
	printf("%lld",ans);
	return 0;
}
posted @ 2020-01-10 14:34  Purple_wzy  阅读(179)  评论(0)    收藏  举报