BZOJ2002弹飞绵羊

来源:互联网 发布:过期备案域名 编辑:程序博客网 时间:2024/04/28 20:09

【题意】我就不多说了;

【题解】我们把 i+k[ i ] 当作是 i 的父亲,这样就是一个求在一棵树上的点到根节点的路径长度。因为这棵树的形态我们不能随便改变,所以可以用(LCA)动态树来做。


#include<cstdio>#include<cstring>#include<cstdlib>#define null 0#define MAX 210000int fa[MAX],left[MAX],right[MAX],size[MAX],t[MAX];  //处理父亲 inline void getfa(int x,int y){     if(t[y]==1)     {                t[y]=0;t[x]=1;     }else     {          if(right[fa[y]]==y)right[fa[y]]=x;           else left[fa[y]]=x;     }     fa[x]=fa[y];} //左旋 inline void Left_Rotate(int x){     int p=fa[x];     getfa(x,p);     size[x]=size[p];     size[p]=size[left[p]]+size[left[x]]+1;     fa[left[x]]=p;     right[p]=left[x];     left[x]=p;     fa[p]=x;} //右旋 inline void Right_Rotate(int x){     int p=fa[x];     getfa(x,p);     size[x]=size[p];     size[p]=size[right[p]]+size[right[x]]+1;     fa[right[x]]=p;     left[p]=right[x];     right[x]=p;     fa[p]=x;} //利用 splay 保持平衡;   void splay(int x){     while(t[x]!=1)     {                   int p=fa[x];                   if(t[p]==1)                   {                              if(x==left[p])Right_Rotate(x);                               else Left_Rotate(x);                              break;                   }else                   if(p==right[fa[p]])                   {                                      if(x==right[p])                                      {                                                     Left_Rotate(p);                                                     Left_Rotate(x);                                      }                                       else {                                                     Right_Rotate(x);                                                     Left_Rotate(x);                                            }                   }else                   {                        if(x==left[p])                        {                                      Right_Rotate(p);                                      Right_Rotate(x);                        }else{                                      Left_Rotate(x);                                      Right_Rotate(x);                              }                   }     }} //实边与虚边的调整(即将从 x 节点到根节点路径上的边都变成实边)  inline void access(int x){     splay(x);     int u=fa[x];     size[x]-=size[right[x]];     t[right[x]]=1;     right[x]=null;           while(u!=null){              splay(u);              t[right[u]]=1;              size[u]=size[u]-size[right[u]]+size[x];              right[u]=x;              t[x]=0;              x=u;              u=fa[u];     }      }void getin(int &x){      x=0;char ch=getchar();      while((ch==' ')||(ch=='\n')||(ch=='\r'))ch=getchar();      while((ch!=' ')&&(ch!='\n')&&(ch!='\r'))x=x*10+(int)ch-48,ch=getchar();}int main(){    int n,l,r,m,p;    memset(right,0,sizeof(right));    memset(left,0,sizeof(left));    size[0]=0;fa[0]=0;         getin(n);    for(int i=1;i<=n;i++)    {            getin(p);            if((i+p)<=n)fa[i]=i+p;             else fa[i]=null;            t[i]=size[i]=1;    }     getin(m);    for(;m;m--)    {            getin(l);            if(l==1){                  getin(r);r++;                  access(r);splay(r);                  printf("%d\n",size[left[r]]+1);             }else if(l==2)            {                 getin(l),getin(r);l++;                 splay(l);                 fa[left[l]]=fa[l];                 t[left[l]]=1;                 //刚开始转移,还是虚边;                  size[l]-=size[left[l]];                 left[l]=null;                 if((l+r)<=n)fa[l]=l+r;                 else fa[l]=null;            }                     }    return 0;   }



0 0
原创粉丝点击