A and B and Lecture Rooms CodeForces - 519E DFS

题目链接:

主要思路:

由于只有n个点,n-1条边,故可以转化为树。

先找到一个离他们最近的与他们距离相等的点,记为点P:

记他们之间的距离为len,若两点之间距离为奇数则答案为0,求出LCA从深度大的那个点开始向上跳(len/2)-1步到X,(根节点深度为0),即跳到P的一个儿子结点上。答案就是sz[p]-sz[X].若他们的深度相同,即他们的LCA就是P,那么答案要加上P的所有祖先(n-sz[p])在减去b能跳到的P的儿子结点的子树的节点个数.如果要查询的两个点在同一位置,则所有结点都满足条件,答案为n(在这里WA了三遍的我表示很重要)。

AC代码:

#include<cstdio>
#include<algorithm>
#define M 100005
using namespace std;
struct E{
	int to,nx;
}edge[M<<1];
int tot,head[M];
void Addedge(int a,int b){
	edge[++tot].to=b;
	edge[tot].nx=head[a];
	head[a]=tot;
}
int fa[M][20],dep[M],sz[M],son[M],top[M],L[M],R[M],T;
void dfs(int now){
	L[now]=++T;
	sz[now]=1;
	son[now]=0;
	for(int i=head[now];i;i=edge[i].nx){
		int nxt=edge[i].to;
		if(nxt==fa[now][0])continue;
		fa[nxt][0]=now;
		dep[nxt]=dep[now]+1;
		dfs(nxt);
		if(sz[son[now]]<sz[nxt])son[now]=nxt;
		sz[now]+=sz[nxt];
	}
	R[now]=T;
}
void dfs_top(int now){//初始化重儿子 
	if(son[now]){
		top[son[now]]=top[now];
		dfs_top(son[now]);
	}
	for(int i=head[now];i;i=edge[i].nx){
		int nxt=edge[i].to;
		if(nxt==son[now]||nxt==fa[now][0])continue;
		top[nxt]=nxt;
		dfs_top(nxt);
	}
}
int LCA(int a,int b){//跳重链求LCA 
	while(top[a]!=top[b]){
		if(dep[top[a]]<dep[top[b]])swap(a,b);
		a=fa[top[a]][0];
	}
	return dep[a]<dep[b]?a:b;
}
void Initfa(int n){
	for(int j=1;j<20;j++){
		for(int i=1;i<=n;i++){
			fa[i][j]=fa[fa[i][j-1]][j-1];
		}
	}
}
void Up(int &x,int y){
	for(int i=0;i<20;i++){
		if(y&(1<<i))x=fa[x][i];
	}
}
int n;
int solve(int a,int b,int x){
	if(a==b)return n;//注意是返回n,不是1
	if(dep[a]<dep[b])swap(a,b);//a为深度大的那个
	int pre=a;
	int cnt=dep[a]+dep[b]-2*dep[x];//算两点之间的距离
	if(cnt%2==1)return 0;//奇数直接返回0
	cnt/=2;
	Up(a,cnt-1);
	int ans=sz[fa[a][0]]-sz[a];
	if(dep[pre]==dep[b]){//若x即为到a与b距离相等且最小的那个点(即P) 
		Up(b,cnt-1); //跳到P的儿子结点 
		return n-sz[x]+ans-sz[b];//还要加上他的所有祖先,减去b跳了之后的子树中结点的个数 
	}
	return ans;
}
int main(){
	dep[1]=1;
	top[1]=1;
	scanf("%d",&n);
	for(int i=1;i<n;i++){
		int a,b;
		scanf("%d%d",&a,&b);
		Addedge(a,b);
		Addedge(b,a);
	}
	dfs(1);
	dfs_top(1);//这样求LCA会快一些 
	Initfa(n);
	int m;
	scanf("%d",&m);
	for(int i=1;i<=m;i++){
		int a,b;
		scanf("%d%d",&a,&b);
		int x=LCA(a,b);
		printf("%d\n",solve(a,b,x));
	}
}

猜你喜欢

转载自blog.csdn.net/qq_35320178/article/details/81433161
今日推荐