2019.01.06 vijos lxhgww的奇思妙想(長鏈剖分)
阿新 • • 發佈:2019-01-08
傳送門
長鏈剖分模板題。
題意簡述:允許
預處理,讓你支援
查詢任意一個點的
級祖先。
思路:因為要
求,因此需要用到長鏈剖分的一些性質。
所謂長鏈剖分是類比重鏈剖分的一種劃分樹的方式,我們考慮將整棵樹用若干條極長鏈拼接起來就是長鏈剖分。
那麼它有如下幾個幾個性質:
- 所有長鏈的長度之和為
- 一個節點的
級祖先所在的長鏈的長度至少為
可以根據長鏈剖分的定義想
然後這題就可以做出來了。
具體實現:
對於長鏈的每一個上頂點
,我們設其引導的長鏈長度為
,我們預處理出
的
~
級祖先和
~
級的長兒子(即它引導的這條鏈),然後用
的時空預處理出一個祖先的倍增陣列以及預處理一個數組
存每個數對應的二進位制位最高位是第幾位。
考慮一個查詢
即查詢
點的
級祖先。
我們先通過倍增陣列將
跳到其
級祖先
,然後剩下的
是小於
的,有性質2可以知道這個祖先一定存在
在的鏈頂上,然後就可以查出來了。
程式碼:
#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;
}