树剖+LCA--bzoj1787: [Ahoi2008]Meet 紧急集合

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/sizeof_you/article/details/83002319

传送门
s o l u t i o n : solution:
这个集结点一定是在三个点到LCA的路径上,而且在任意两点的LCA中的某一个上,所以就把三个LCA算出来都算一下花费的钱数取最小的

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#define N 500005
using namespace std;
int n,m,cnt,head[N],ans,p;
int tot,dfn[N],dep[N],rk[N],fa[N],siz[N],top[N],son[N];

inline int rd(){
	int x=0,f=1;char c=' ';
	while(c<'0' || c>'9') f=c=='-'?-1:1,c=getchar();
	while(c<='9' && c>='0') x=x*10+c-'0',c=getchar();
	return x*f;
}
inline int max(int x,int y){return x>y?x:y;}

struct EDGE{
	int to,nxt;
}edge[N<<1];

inline void add(int x,int y){
	edge[++cnt].to=y; edge[cnt].nxt=head[x]; head[x]=cnt;
}

inline void dfs1(int u,int fat,int depth){
	dep[u]=depth,fa[u]=fat,siz[u]=1;
	int maxson=-1;
	for(int i=head[u];i;i=edge[i].nxt){
		int v=edge[i].to; if(v==fat) continue;
		dfs1(v,u,depth+1); siz[u]+=siz[v];
		if(siz[v]>maxson) son[u]=v,maxson=siz[v];
	} return;
}

inline void dfs2(int u,int topf){
	dfn[u]=++tot; rk[tot]=u; top[u]=topf;
	if(!son[u]) return;
	dfs2(son[u],topf);
	for(int i=head[u];i;i=edge[i].nxt){
		int v=edge[i].to;
		if(!dfn[v]) dfs2(v,v);
	}
}

inline int LCA(int x,int y){
	while(top[x]!=top[y]){
		if(dep[top[x]]>=dep[top[y]]) x=fa[top[x]];
		else y=fa[top[y]];
	}
	return dep[x]<dep[y]?x:y;
}

int main(){
	n=rd(); m=rd();
	for(int i=1;i<n;i++){
		int x=rd(),y=rd();
		add(x,y); add(y,x);
	}
	dfs1(1,0,1); dfs2(1,1);
	for(int i=1;i<=m;i++){
		int x=rd(),y=rd(),z=rd();
		int a=LCA(x,y),b=LCA(y,z),c=LCA(x,z),d=LCA(a,b);
		int tmp=dep[x]+dep[y]+dep[z];
		if(dep[a]>=dep[b] && dep[a]>=dep[c])
			ans=tmp-dep[a]-2*dep[d],p=a;
		else if(dep[b]>=dep[a] && dep[b]>=dep[c])
			ans=tmp-dep[b]-2*dep[d],p=b;
		else ans=tmp-dep[c]-2*dep[d],p=c;
		printf("%d %d\n",p,ans);
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/sizeof_you/article/details/83002319
今日推荐