1. 程式人生 > >2019.01.06 vijos lxhgww的奇思妙想(長鏈剖分)

2019.01.06 vijos lxhgww的奇思妙想(長鏈剖分)

傳送門
長鏈剖分模板題。
題意簡述:允許 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;
}