LCA【SP913】Qtree - Query on a tree II

Description

给定一棵n个点的树,边具有边权。要求作以下操作:

DIST a b 询问点a至点b路径上的边权之和

KTH a b k 询问点a至点b有向路径上的第k个点的编号

有多组测试数据,每组数据以DONE结尾。

Input

第一组数据包含一个整数\(T\),代表有\(T\)组测试数据。\(1\leq T \leq 25\)

对每一组测试数据:

  • 第一行一个整数\(N(n \leq 10000)\)
  • 接下来有\(N-1\)行,每一行描述树上的一条边\(a,b,c( c\leq 100000)\)
  • 接下来几行操作包括\(DIST \ a \ b\),\(KTH \ a \ b \ k\)
  • \(DONE\)结尾

Output

对于每一个\(DIST\)\(KTH\)询问输出一行.

很明显,LCA,但是难点就在于如何求出\(KTH\)对于的答案.

首先会存在两种情况

一. \(k \leq depth[x]-depth[lca_{x,y}]+1\)

很明显,这时第\(k\)个点必然在于\(x->lca_{x,y}\)的路径上,我们只需要知道其深度即可倍增求取.

可求其深度为\(depth[x]-k+1\)

二. \(k > depth[x]-depth[lca_{x,y}]+1\)

这时,第\(k\)个点必然存在于\(y->lca_{x,y}\)的路径上,但是如何求其深度却是一个问题.

先设\(ans\)为第\(k\)个点的深度.

我们可以得到的信息是\(k\)必须要在\(y->lca_{x,y}\)

所以新的深度至少必须为\(k-(depth[x]-depth[lca_{x,y}]+1)\)

但是由于我们的\(lca_{x,y}\)不一定为\(1\)(这里我以\(1\)为根)

所以原式子还需要加上一个\(depth[lca_{x,y}]\)

因此可以得到这样一个式子

\[ans=k-depth[x]+2*depth[lca_{x,y}]-1; \]

知道深度之后,直接倍增跳即可.

代码

#include<cstdio>
#include<cctype>
#include<cstring>
#include<algorithm>
#define clear(a) memset(a,0,sizeof a)
#define N 10008
#define R register
using namespace std;
inline void in(int &x)
{
	int f=1;x=0;char s=getchar();
	while(!isdigit(s)){if(s=='-')f=-1;s=getchar();}
	while(isdigit(s)){x=x*10+s-'0';s=getchar();}
	x*=f;
}
int T;
int n,head[N],tot;
struct cod{int u,v,w;}edge[N<<2];
inline void add(int x,int y,int z)
{
	edge[++tot].u=head[x];
	edge[tot].v=y;
	edge[tot].w=z;
	head[x]=tot;
}
int depth[N],f[N][21],dis[N];
void dfs(int u,int fa,int dist)
{
	f[u][0]=fa;dis[u]=dis[fa]+dist;depth[u]=depth[fa]+1;
	for(R int i=1;(1<<i)<=depth[u];i++)
		f[u][i]=f[f[u][i-1]][i-1];
	for(R int i=head[u];i;i=edge[i].u)
	{
		if(edge[i].v==fa)continue;
		dfs(edge[i].v,u,edge[i].w);
	}
}
inline int lca(int x,int y)
{
	if(depth[x]>depth[y])swap(x,y);
	for(R int i=17;i>=0;i--)
		if(depth[x]+(1<<i)<=depth[y])
			y=f[y][i];
	if(x==y)return y;
	for(R int i=17;i>=0;i--)
	{
		if(f[x][i]==f[y][i])continue;
		x=f[x][i],y=f[y][i];
	}
	return f[x][0];
}
char s[108];
inline int query(int x,int y,int k)
{
	R int la=lca(x,y);
	if(depth[x]-depth[la]+1>=k)
	{
		R int ans=depth[x]-k+1;
		for(R int i=17;i>=0;i--)
		{
			if(depth[x]-ans>=(1<<i))
				x=f[x][i];
		}
		return x;
	}
	else
	{
		R int ans=depth[la]*2+k-depth[x]-1;
		for(R int i=17;i>=0;i--)
			if((1<<i)<=depth[y]-ans)
				y=f[y][i];
		return y;
	}
}
int main()
{
	in(T);
	for(;T;T--)
	{
		in(n);
		tot=0;clear(head),clear(dis),clear(f);clear(depth);
		for(R int i=1,x,y,z;i<n;i++)
		{
			in(x),in(y),in(z);
			add(x,y,z);add(y,x,z);
		}
		dfs(1,0,0);
		for(R int x,y,la,k;;)
		{
			scanf("%s",s+1);
			if(s[2]=='O')break;
			if(s[2]=='I')
			{
				in(x),in(y);
				la=lca(x,y);
				printf("%d\n",dis[x]+dis[y]-2*dis[la]);
			}
			else
			{
				in(x),in(y),in(k);
				printf("%d\n",query(x,y,k));
			}
		}
	}
}
posted @ 2018-10-20 20:38  顾z  阅读(236)  评论(0编辑  收藏  举报