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

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

題目

lxhgww在樹上玩耍時,LZX2019走了過來。lxhgww突然問道:“我現在的k級祖先是誰?”
LZX2019答道:“不是我嗎?”。接著lxhgww就用教主之力讓LZX2019消失了,現在他轉過頭準備向你求助。

 

長鏈剖分的板子(又是亂搞優化暴力)

對於每一個點,我們定義它深度最深的子節點為它的重兒子(為什麼不叫長兒子……),他們之間的連邊為重邊

然後長鏈剖分有幾個性質

1.總鏈長為$O(n)$

2.一個節點的$k$級祖先的子樹深度必定大於等於當前節點的子樹深度

以上兩點稍微yy一下就能發現是對的

然後回到這道題。我們設$len[u]$為這一條長鏈的長度,對於每一個長鏈的頂點,我們維護它的1到$len[u]$級兒子以及1到$len[u]$級祖先

同時預處理找祖先的倍增陣列,並預處理出1到$n$的每一個數字的二進位制最高位即$highbit$

那麼對於每一個詢問$(u,k)$,我們設$r=highbit(k)$,那麼我們用預處理的倍增陣列讓$u$跳到它的$r$級祖先$v$處

因為$k-r<r$,那麼$v$的長鏈的長度$\geq r>k-r$,那麼$v$所在的長鏈預處理的表一定已經包含了$u$的$k$級祖先

時間複雜度為$O(nlogn+m)$,預處理$O(nlogn)$,每一次回答$O(1)$

 1 //minamoto
 2 #include<iostream>
 3 #include<cstdio>
 4
#include<vector> 5 using namespace std; 6 #define getc() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++) 7 char buf[1<<21],*p1=buf,*p2=buf; 8 int read(){ 9 #define num ch-'0' 10 char ch;bool flag=0;int res; 11 while(!isdigit(ch=getc()))
12 (ch=='-')&&(flag=true); 13 for(res=num;isdigit(ch=getc());res=res*10+num); 14 (flag)&&(res=-res); 15 #undef num 16 return res; 17 } 18 char sr[1<<21],z[20];int C=-1,Z; 19 inline void Ot(){fwrite(sr,1,C+1,stdout),C=-1;} 20 void print(int x){ 21 if(C>1<<20)Ot();if(x<0)sr[++C]=45,x=-x; 22 while(z[++Z]=x%10+48,x/=10); 23 while(sr[++C]=z[Z],--Z);sr[++C]='\n'; 24 } 25 const int N=3e5+5; 26 int head[N],Next[N<<1],ver[N<<1],tot; 27 inline void add(int u,int v){ 28 ver[++tot]=v,Next[tot]=head[u],head[u]=tot; 29 } 30 int n,md[N],dep[N],fa[N][21],son[N],top[N],len[N],B[N]; 31 vector<int> U[N],D[N]; 32 void dfs(int u,int f){ 33 md[u]=dep[u]=dep[f]+1,fa[u][0]=f; 34 for(int i=1;i<20;++i) 35 if(fa[u][i-1]) fa[u][i]=fa[fa[u][i-1]][i-1]; 36 else break; 37 for(int i=head[u];i;i=Next[i]){ 38 int v=ver[i]; 39 if(v!=f){ 40 dfs(v,u); 41 if(md[son[u]]<md[v]) son[u]=v,md[u]=md[v]; 42 } 43 } 44 } 45 void dfs2(int u,int t){ 46 top[u]=t,len[u]=md[u]-dep[t]+1; 47 if(son[u]){ 48 dfs2(son[u],t); 49 for(int i=head[u];i;i=Next[i]) 50 if(!top[ver[i]]) dfs2(ver[i],ver[i]); 51 } 52 } 53 void init(){ 54 int now=0; 55 for(int i=1;i<=n;++i){ 56 if(!(i&(1<<now))) ++now; 57 B[i]=now; 58 } 59 for(int i=1;i<=n;++i) 60 if(i==top[i]){ 61 for(int j=1,u=i;j<=len[i]&&u;++j) u=fa[u][0],U[i].push_back(u); 62 for(int j=1,u=i;j<=len[i]&&u;++j) u=son[u],D[i].push_back(u); 63 } 64 } 65 int query(int u,int k){ 66 if(k>dep[u]) return 0;if(k==0) return u; 67 u=fa[u][B[k]],k^=1<<B[k]; 68 if(k==0) return u; 69 if(dep[u]-dep[top[u]]==k) return top[u]; 70 if(dep[u]-dep[top[u]]<k) return U[top[u]][k-dep[u]+dep[top[u]]-1]; 71 else return D[top[u]][dep[u]-dep[top[u]]-k-1]; 72 } 73 int main(){ 74 // freopen("testdata.in","r",stdin); 75 n=read(); 76 for(int i=1;i<n;++i){ 77 int u=read(),v=read(); 78 add(u,v),add(v,u); 79 } 80 dfs(1,0),dfs2(1,1),init(); 81 int lastans=0,q=read(); 82 while(q--){ 83 int u=read()^lastans,v=read()^lastans; 84 printf("%d\n",lastans=query(u,v)); 85 } 86 return Ot(),0; 87 }