「WC2018」通道(边分治套虚树)

题目
先考虑两棵树怎么做。
我们在第二棵树的每一个点 u u 上再挂一个点 u u' ,他们的距离为第一棵树上的 d e p u dep_u
那么在第二棵树上的两点 u , v u',v' 的距离就是两棵树上距离总和- u , v u,v 在第一棵树上的 l c a lca 的深度 × 2 \times 2
考虑枚举这个 l c a lca ,那么答案就应该是 l c a lca 的两个不同子树 S 1 , S 2 S1,S2 ,求 u S 1 , v S 2 u'\in S1,v'\in S2 的在第二棵树上的 d i s ( u , v ) dis(u',v') 的最大值- l c a lca 的深度 × 2 \times 2
两个点集间的最长距离的两个端点一定可以是在两个点集各自的直径端点中各取一个。
所以就动态维护点集直径即可,
时间复杂度 O ( n log n ) O(n\log n)
如果 O ( 1 ) L C A O(1)LCA 的话就是预处理 O ( n log n ) O(n\log n) 解答 O ( n ) O(n)

再加入一颗树。
那么在第三颗树上边分治,把一个点集 S S 分成两个集合 S 1 , S 2 S1,S2
那么我们在第一棵树上建立点集 S S 的虚树,
然后对于第一棵树和第二棵树我们用之前的做法不过现在我们要更新答案,
两个端点不能同在 S 1 S1 或同在 S 2 S2
简单 D P DP 一下即可。
时间复杂度 O ( n log n s o r t ( n ) + n log n ) O(n\log n * sort(n) + n\log n)
用基排好像可以 O ( n log n ) O(n\log n) 的理性愉悦一下。

我居然只是小小的调了几个错而已。
这代码比紫荆花之恋和希望都长,应该是我目前最长的代码了

A C   C o d e \mathrm {AC \ Code}

#include<bits/stdc++.h>
#define maxn 400005
#define LL long long
#define Ct const
#define lim 19
#define rep(i,j,k) for(int i=(j),LIM=(k);i<=LIM;i++)
#define per(i,j,k) for(int i=(j),LIM=(k);i>=LIM;i--)
#define ADJ(i,u) for(int i=info[u],v;i;i=Prev[i])
using namespace std;

char cb[1<<16],*cs=cb,*ct=cb;
#define getc() (cs==ct&&(ct=(cs=cb)+fread(cb,1,1<<16,stdin),cs==ct)?0:*cs++)
template<class T>void read(T &res){char ch;for(;!isdigit(ch=getc()););for(res=ch-'0';isdigit(ch=getc());res=res*10+ch-'0');}

int n,lg[maxn];
LL ans;

void PrePare_ST(int MN[lim][maxn],int *dep,int n){ rep(j,1,lim-1)rep(i,0,n-(1<<j)+1)MN[j][i]=dep[MN[j-1][i]]<dep[MN[j-1][i+(1<<j-1)]]?MN[j-1][i]:MN[j-1][i+(1<<j-1)];  }
namespace Tree1{
	int info[maxn],Prev[maxn<<1],to[maxn<<1],cnt_e;
	LL dep[maxn],cst[maxn<<1],adep[maxn];
	int MN[lim][maxn],ptdep[maxn],st[maxn],dfn;
	void Node(int u,int v,LL w){ Prev[++cnt_e]=info[u],info[u]=cnt_e,to[cnt_e]=v,cst[cnt_e]=w; }
	void dfs(int u,int ff){
		MN[0][st[u] = ++dfn]=u;
		ADJ(i,u) if((v=to[i])^ff) dep[v]=dep[u]+cst[i],ptdep[v]=ptdep[u]+1,dfs(v,u),MN[0][++dfn]=u;
	}
	void init(){
		int u,v;LL w;
		rep(i,1,n-1) read(u),read(v),read(w),Node(u,v,w),Node(v,u,w);
	}
	int LCA(int u,int v){
		u = st[u] , v = st[v];
		if(u > v) swap(u,v);
		int t = lg[v-u+1];
		return ptdep[MN[t][u]]<ptdep[MN[t][v-(1<<t)+1]]?MN[t][u]:MN[t][v-(1<<t)+1];
	}
	LL dis(int u,int v){ if(!u || !v) return 0;u+=n,v+=n; return adep[u] + adep[v] + dep[u] + dep[v] - 2 * dep[LCA(u,v)]; }
}
using Tree1::dis;
int ar[maxn];
namespace Tree2{
	int info[maxn],Prev[maxn<<1],to[maxn<<1],cnt_e;
	LL dep[maxn],cst[maxn<<1];
	int MN[lim][maxn],ptdep[maxn],st[maxn],col[maxn],dfn;
	void Node(int u,int v,LL w){ Prev[++cnt_e]=info[u],info[u]=cnt_e,to[cnt_e]=v,cst[cnt_e]=w; }
	void dfs(int u,int ff){
		MN[0][st[u] = ++dfn]=u;Tree1::Node(u,u+n,dep[u]);
		ADJ(i,u) if((v=to[i])^ff) dep[v]=dep[u]+cst[i],ptdep[v]=ptdep[u]+1,dfs(v,u),MN[0][++dfn]=u;
	}
	void init(){
		int u,v;LL w;
		rep(i,1,n-1) read(u),read(v),read(w),Node(u,v,w),Node(v,u,w);
		dfs(1,0);
		PrePare_ST(MN,ptdep,dfn);
		Tree1::dfs(1,0);
		PrePare_ST(Tree1::MN,Tree1::ptdep,Tree1::dfn);
	}
	int LCA(int u,int v){
		u = st[u] , v = st[v];
		if(u > v) swap(u,v);
		int t = lg[v-u+1];
		return ptdep[MN[t][u]]<ptdep[MN[t][v-(1<<t)+1]]?MN[t][u]:MN[t][v-(1<<t)+1];
	}
	bool cmp(Ct int &u,Ct int &v){ return st[u]<st[v]; }
	int f[maxn][2][2];
	void merge(int u,int v){
		rep(i,0,1) rep(j,0,1) rep(k,0,1)ans = max(ans , dis(f[u][i][j],f[v][i^1][k]) - 2 * dep[u]);
		rep(i,0,1){
			int a=f[u][i][0],b=f[u][i][1];LL d=dis(a,b),t;
			rep(j,0,1) rep(k,0,1) if((t=dis(f[u][i][j],f[v][i][k]))>d || (!a && !b))
				d=t,a=f[u][i][j],b=f[v][i][k];
			if((t=dis(f[v][i][0],f[v][i][1]))>d || (!a && !b))
				d=t,a=f[v][i][0],b=f[v][i][1];
			f[u][i][0]=a,f[u][i][1]=b;
		}
	}
	void newnode(int u){  
		if(!col[u]) f[u][0][0] = f[u][0][1] = f[u][1][0] = f[u][1][1] = 0;
		if(col[u] == 1) f[u][0][0] = f[u][0][1] = u , f[u][1][0] = f[u][1][1] = 0;
		if(col[u] == 2) f[u][0][0] = f[u][0][1] = 0 , f[u][1][0] = f[u][1][1] = u;
	}
	void Solve(){
		sort(ar+1,ar+1+ar[0],cmp);
		static int q[maxn],R=0;
		rep(i,1,ar[0]){
			if(R){
				int t=LCA(q[R],ar[i]),p=0;
				for(;R&&ptdep[q[R]]>ptdep[t];p=q[R--]) if(p) merge(q[R],p);
				if(q[R]^t) q[++R]=t,newnode(t);
				if(p) merge(q[R],p);
			}
			q[++R]=ar[i],newnode(ar[i]);
		} 
		for(int p=0;R;p=q[R--])
			if(p) merge(q[R],p);
	}
}
namespace Tree3{
	int info[maxn],Prev[maxn<<1],to[maxn<<1],cnt_e;
	LL dep[maxn],cst[maxn<<1],cts[maxn<<1];
	void Node(int u,int v,LL w){ Prev[++cnt_e]=info[u],info[u]=cnt_e,to[cnt_e]=v,cst[cnt_e]=w; }
	int fir[maxn],tar[maxn<<1],nxt[maxn<<1],cnte=1;
	void add(int u,int v,LL w=0){ nxt[++cnte]=fir[u],fir[u]=cnte,tar[cnte]=v,cts[cnte]=w; }
	void lin(int u,int v,LL w=0){ add(u,v,w),add(v,u,w); }
	int N,sz[maxn];bool vis[maxn];
	void Build(int u,int ff){
		int p=0;
		ADJ(i,u) if((v=to[i])^ff) Build(v,u),++N,p&&(lin(N,p),0),lin(p=N,v,cst[i]);
		if(p) lin(u,p);
	}
	void dfs(int u,int ff,int tsz,int &mn,int &rt){
		sz[u] = 1;
		for(int i=fir[u],v;i;i=nxt[i]) if((v=tar[i])^ff && !vis[i]){
			dfs(v,u,tsz,mn,rt),sz[u]+=sz[v];
			if(max(sz[v],tsz-sz[v]) < mn)
				mn = max(sz[v] , tsz-sz[v]) , rt = i;
		}
	}
	int Gert(int u,int tsz){
		static int mn,rt;
		dfs(u,0,tsz,mn=0x3f3f3f3f,rt=-1);
		return rt;
	}
	void ser(int u,int ff,LL d,int tp){
		if(u<=n)
			Tree1::adep[u+n] = d,
			ar[++ar[0]] = u;
		Tree2::col[u] = tp;
		sz[u] = 1;
		for(int i=fir[u],v;i;i=nxt[i])
		 if((v=tar[i])^ff && !vis[i]) ser(v,u,d+cts[i],tp),sz[u]+=sz[v];
	}
	void Solve(int u){
		if(u == -1) return;
		vis[u] = vis[u^1] = 1;
		ar[0] = 0;
		ser(tar[u],0,cts[u],1);
		ser(tar[u^1],0,0,2);
		Tree2::Solve();
		Solve(Gert(tar[u],sz[tar[u]])),Solve(Gert(tar[u^1],sz[tar[u^1]]));
	}
	void init(){
		int u,v;LL w;
		rep(i,1,n-1) read(u),read(v),read(w),Node(u,v,w),Node(v,u,w);
		N=n;Build(1,0);
		Solve(Gert(1,N));
	}
}

int main(){
//	freopen("1.in","r",stdin);
//	freopen("1.out","w",stdout);
	rep(i,2,maxn-1) lg[i]=lg[i>>1]+1; 
	scanf("%d",&n);
	Tree1::init(),Tree2::init(),Tree3::init();
	printf("%lld\n",ans);
}
发布了630 篇原创文章 · 获赞 92 · 访问量 9万+

猜你喜欢

转载自blog.csdn.net/qq_35950004/article/details/104010316
今日推荐