bzoj 2002

LCT板子题...

看到题目中的操作很显然是从$i$向$i+k_{i}$连一条边,每次修改就是删除原来的边再加入一条新的边嘛

然后考虑查询:对于被弹飞的部分,我们统一新建一个节点$n+1$,把所有越过边界的部分指向这个节点即可

然后在查询的时候只需要拎出查询节点到$n+1$节点的树链,统计其大小即可

注意节点编号读入时加一

贴代码:

#include <cstdio>
#include <cmath>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#include <queue>
#include <stack>
using namespace std;
int siz[200005];
int ch[200005][2];
int fl[200005],f[200005];
int to[200005];
int n,m;
void update(int x)
{
    siz[x]=siz[ch[x][0]]+siz[ch[x][1]]+1;
}
bool be_root(int x)
{
    if(ch[f[x]][0]==x||ch[f[x]][1]==x)return 0;
    return 1;
}
void pushdown(int x)
{
    if(fl[x])
    {
        swap(ch[ch[x][0]][0],ch[ch[x][0]][1]);
        swap(ch[ch[x][1]][0],ch[ch[x][1]][1]);
        fl[ch[x][0]]^=1,fl[ch[x][1]]^=1;
        fl[x]=0;
    }
}
void repush(int x)
{
    if(!be_root(x))repush(f[x]);
    pushdown(x);
}
void rotate(int x)
{
    int y=f[x],z=f[y],k=(ch[y][1]==x);
    if(!be_root(y))ch[z][ch[z][1]==y]=x;
    f[x]=z;
    ch[y][k]=ch[x][!k],f[ch[x][!k]]=y;
    ch[x][!k]=y,f[y]=x;
    update(y),update(x);
}
void splay(int x)
{
    repush(x);
    while(!be_root(x))
    {
        int y=f[x],z=f[y];
        if(!be_root(y))
        {
            if((ch[y][1]==x)^(ch[z][1]==y))rotate(x);
            else rotate(y);
        }
        rotate(x);
    }
    update(x);
}
void access(int x)
{
    int y=0;
    while(x)
    {
        splay(x);
        ch[x][1]=y;
        update(x);
        y=x,x=f[x];
    }
}
int get_root(int x)
{
    access(x),splay(x);
    while(ch[x][0])pushdown(x),x=ch[x][0];
    return x;
}
void make_root(int x)
{
    access(x),splay(x);
    swap(ch[x][0],ch[x][1]),fl[x]^=1;
}
void link(int x,int y)
{
    make_root(x);
    if(get_root(y)!=x)f[x]=y;
}
void cut(int x,int y)
{
    make_root(y);
    if(get_root(x)==y&&f[y]==x&&!ch[y][1])ch[x][0]=f[y]=0,update(x);
}
inline int read()
{
    int f=1,x=0;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    return x*f;
}
int main()
{
    n=read();
    for(int i=1;i<=n;i++)to[i]=read(),link(i,min(i+to[i],n+1));
    m=read();
    while(m--)
    {
        int typ=read();
        if(typ==1)
        {
            int x=read()+1;
            make_root(x),access(n+1),splay(n+1);
            printf("%d\n",siz[n+1]-1);
        }else
        {
            int x=read()+1,y=read();
            cut(x,min(x+to[x],n+1));
            to[x]=y;
            link(x,min(x+to[x],n+1));
        }
    }
    return 0;
}

 

posted @ 2019-07-10 10:55  lleozhang  Views(64)  Comments(0Edit  收藏
levels of contents