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

传送门

 

长链剖分的板子(又是乱搞优化暴力)

对于每一个点,我们定义它深度最深的子节点为它的重儿子(为什么不叫长儿子……),他们之间的连边为重边

然后长链剖分有几个性质

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 }

 

posted @ 2018-10-19 19:04  bztMinamoto  阅读(281)  评论(0编辑  收藏  举报
Live2D