BZOJ2002弹飞绵羊

【题意】我就不多说了;

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


#include<cstdio>
#include<cstring>
#include<cstdlib>
#define null 0
#define MAX 210000
int 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;   
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值