vijos lxhgww的奇思妙想 长链剖分

版权声明:转吧转吧这条东西只是来搞笑的。。 https://blog.csdn.net/jpwang8/article/details/89281683

Description


给一棵n个节点的树,m次询问一个节点x的k级祖先。强制在线

Solution


一个做法是倍增
另一个做法是长链剖分。同重链剖分一样,我们定义深度最大叶子所在儿子作为长儿子。

一个性质是,节点x的k级祖先所在重链长度不会小于k。正确性的话可以考虑反证一下。

也就是说,我们取出k的最高位二进制设为r。我们先让x向上跳r步,r所在的重链长度至少为r。对于每条重链我们维护它向上len个节点,沿着重链向下len个节点。那么剩下的k-r步我们可以一次跳完

于是这样做就是O(nlogn)预处理倍增,O(1)求一个节点的k级祖先

Code


#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <vector>
#define rep(i,st,ed) for (int i=st;i<=ed;++i)
#define drp(i,st,ed) for (int i=st;i>=ed;--i)

const int N=1000005;

struct edge {int y,next;} e[N*2];

int bl[N],mx[N],dep[N],fa[19][N];
int ls[N],high[N],edCnt;
int son[N],len[N];

std:: vector <int> U[N],D[N];

int read() {
	int x=0,v=1; char ch=getchar();
	for (;ch<'0'||ch>'9';v=(ch=='-')?(-1):v,ch=getchar());
	for (;ch<='9'&&ch>='0';x=x*10+ch-'0',ch=getchar());
	return x*v;
}

void add_edge(int x,int y) {
	e[++edCnt]=(edge) {y,ls[x]}; ls[x]=edCnt;
	e[++edCnt]=(edge) {x,ls[y]}; ls[y]=edCnt;
}

void dfs1(int x) {
	int rec=0; mx[x]=dep[x];
	rep(i,1,18) fa[i][x]=fa[i-1][fa[i-1][x]];
	for (int i=ls[x];i;i=e[i].next) {
		if (e[i].y==fa[0][x]) continue;
		dep[e[i].y]=dep[x]+1,fa[0][e[i].y]=x;
		dfs1(e[i].y);
		if (mx[e[i].y]>mx[son[x]]) {
			mx[x]=mx[e[i].y];
			son[x]=e[i].y;
		}
	}
}

void dfs2(int x,int up) {
	bl[x]=up; len[x]=mx[x]-dep[up]+1;
	if (!son[x]) return ;
	dfs2(son[x],up);
	for (int i=ls[x];i;i=e[i].next) {
		if (e[i].y!=fa[0][x]&&e[i].y!=son[x]) dfs2(e[i].y,e[i].y);
	}
}

int get_up(int x,int k) {
	if (k>dep[x]) return 0;
	if (!k) return x;
	x=fa[high[k]][x],k-=(1<<high[k]);
	if (!k) return x;
	int up=bl[x];
	if (dep[x]-dep[up]==k) return up;
	if (dep[x]-dep[up]<k) return U[up][k-dep[x]+dep[up]-1];
	else return D[up][dep[x]-dep[up]-k-1];
}

int main(void) {
	int n=read();
	rep(i,1,n) {
		high[i]=high[i-1];
		if (i>>high[i]&1) continue;
		high[i]++;
	}
	rep(i,2,n) add_edge(read(),read());
	dfs1(1); dfs2(1,1);
	rep(i,1,n) if (bl[i]==i) {
		for (int x=i,d=1;d<=len[i]&&x;d++) x=fa[0][x],U[i].push_back(x);
		for (int x=i,d=1;d<=len[i]&&x;d++) x=son[x],D[i].push_back(x);
	}
	for (int m=read(),lastans=0;m--;) {
		int x=read(),y=read();
		x^=lastans,y^=lastans;
		lastans=get_up(x,y);
		printf("%d\n", lastans);
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/jpwang8/article/details/89281683