2019.01.06 vijos lxhgww的奇思妙想(长链剖分)

版权声明:随意转载哦......但还是请注明出处吧: https://blog.csdn.net/dreaming__ldx/article/details/85955182

传送门
长链剖分模板题。
题意简述:允许 O ( n l o g n ) O(nlog_n) 预处理,让你支持 O ( 1 ) O(1) 查找任意一个点的 k k 级祖先。


思路:因为要 O ( 1 ) O(1) 求,因此需要用到长链剖分的一些性质。
所谓长链剖分是类比重链剖分的一种划分树的方式,我们考虑将整棵树用若干条极长链拼接起来就是长链剖分。
那么它有如下几个几个性质:

  1. 所有长链的长度之和为 O ( n ) O(n)
  2. 一个节点的 k k 级祖先所在的长链的长度至少为 k k 可以根据长链剖分的定义想
    然后这题就可以做出来了。

具体实现:
对于长链的每一个上顶点 p p ,我们设其引导的长链长度为 l e n len ,我们预处理出 p p 0 0 ~ l e n len 级祖先和 0 0 ~ l e n len 级的长儿子(即它引导的这条链),然后用 O ( n l o g n ) O(nlogn) 的时空预处理出一个祖先的倍增数组以及预处理一个数组 h i g h b i t highbit 存每个数对应的二进制位最高位是第几位。
考虑一个查询 ( p , r ) (p,r) 即查询 p p 点的 r r 级祖先。
我们先通过倍增数组将 p p 跳到其 2 h i g h b i t r 2^{highbit_{r}} 级祖先 y y ,然后剩下的 r h i g h b i t r r-highbit_r 是小于 h i g h b i t r highbit_r 的,有性质2可以知道这个祖先一定存在 y y 在的链顶上,然后就可以查出来了。
代码:

#include<bits/stdc++.h>
#define ri register int
using namespace std;
inline int read(){
	int ans=0;
	char ch=getchar();
	while(!isdigit(ch))ch=getchar();
	while(isdigit(ch))ans=(ans<<3)+(ans<<1)+(ch^48),ch=getchar();
	return ans;
}
const int N=3e5+5;
int top[N],st[N][21],Log[N],n,m,dep[N],hson[N],mdep[N],highbit[N];
vector<int>e[N],son[N],anc[N];
inline void init(){
	Log[1]=0,highbit[1]=0;
	for(ri i=2;i<=n;++i)Log[i]=Log[i>>1]+1,highbit[i]=highbit[i-1]+(i>>(highbit[i-1]+1)&1);
	for(ri i=1;i<=n;++i){
		if(top[i]==i){
			int up=mdep[i]-dep[i];
			for(ri v=i,j=0;j<=up;++j)son[i].push_back(v),v=hson[v];
			for(ri v=i,j=0;j<=up;++j)anc[i].push_back(v),v=st[v][0];
		}
	}
	for(ri j=1;j<=20;++j)for(ri i=1;i<=n;++i)st[i][j]=st[st[i][j-1]][j-1];
}
void dfs1(int p){
	for(ri v,i=0;i<e[p].size();++i){
		if((v=e[p][i])==st[p][0])continue;
		st[v][0]=p,mdep[v]=dep[v]=dep[p]+1,dfs1(v),mdep[p]=max(mdep[v],mdep[p]);
		if(mdep[v]>mdep[hson[p]])hson[p]=v;
	}
}
void dfs2(int p,int tp){
	top[p]=tp;
	if(!hson[p])return;
	dfs2(hson[p],tp);
	for(ri i=0,v;i<e[p].size();++i){
		v=e[p][i];
		if(v==st[p][0]||v==hson[p])continue;
		dfs2(v,v);
	}
}
inline int query(int x,int k){
	if(k>dep[x])return 0;
	if(!k)return x;
	int y=st[x][highbit[k]];
	k-=1<<highbit[k];
	if(!k)return y;
	if(dep[y]-dep[top[y]]<=k)return anc[top[y]][k-dep[y]+dep[top[y]]];
	return son[top[y]][dep[y]-dep[top[y]]-k];
}
int main(){
	n=read();
	for(ri i=1,u,v;i<n;++i)u=read(),v=read(),e[u].push_back(v),e[v].push_back(u);
	dfs1(1),dfs2(1,1),init();
	for(ri tt=read(),lastans=0,x,k;tt;--tt)x=read()^lastans,k=read()^lastans,cout<<(lastans=query(x,k))<<'\n';
	return 0;
}

猜你喜欢

转载自blog.csdn.net/dreaming__ldx/article/details/85955182