• 「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]='
    ';
    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
    ",lastans=query(u,v));
    85     }
    86     return Ot(),0;
    87 }
  • 相关阅读:
    svn使用
    canvas入门-3渐变方法
    canvas入门-2路径、文字
    canvas入门-1三种填充方式、渐变、模式
    jquery extend的使用
    angular入门-ngOptions
    jquery-EasyUI---panel面板的用法
    jquery-EasyUI---tooltip提示框的使用
    jquery-EasyUI---progressbar进度条的的使用
    jquery-EasyUI---searchbox搜索框的用法
  • 原文地址:https://www.cnblogs.com/bztMinamoto/p/9818224.html
Copyright © 2020-2023  润新知