[bzoj] 2002 弹飞绵羊 || LCT

Posted Mrha

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[bzoj] 2002 弹飞绵羊 || LCT相关的知识,希望对你有一定的参考价值。

原题

简单的LCT练习题。
我们发现对于一个位置x,他只能跳到位置x+k,也就是唯一的父亲去。加入我们将弹飞的绵羊定义为跳到了n+1,那么这就形成了一棵树。而因为要修改k,所以这颗树是动态连边的,那么LCT就可以解决了。
至于询问,我们把n+1变成根,然后access(x)将x到n+1的路径变为实路径,splay(x),因为每次是向父亲弹,所以sze[ls[x]]即为答案。
//想知道为什么不是sze[x]-1

AC代码:

#include<cstdio>
#include<algorithm>
#define N 200010
#define which(u) (ls[fa[(u)]]==(u))
#define isroot(u) (!fa[(u)] || (ls[fa[(u)]]!=(u) && rs[fa[u]]!=(u)))
using namespace std;
int n,m,fa[N],ls[N],rs[N],a[N],sze[N];
bool rev[N];
char s[20];

void update(int x)
{
    sze[x]=1;
    if (ls[x]) sze[x]+=sze[ls[x]];
    if (rs[x]) sze[x]+=sze[rs[x]];
}

void rotate(int u)
{
    int v=fa[u],w=fa[v],b=which(u)?rs[u]:ls[u];
    if (!isroot(v)) (which(v)?ls[w]:rs[w])=u;
    which(u)?(ls[v]=b,rs[u]=v):(rs[v]=b,ls[u]=v);
    fa[u]=w,fa[v]=u;
    if (b) fa[b]=v;
    if (v) update(v);
    if (u) update(u);
}

void pushdown(int u)
{
    if (!rev[u]) return ;
    rev[ls[u]]^=1;
    rev[rs[u]]^=1;
    swap(ls[u],rs[u]);
    rev[u]=0;
}

void splay(int u)
{
    static int stk[N],top;
    stk[top=1]=u;
    while (!isroot(stk[top])) stk[top+1]=fa[stk[top]],top++;
    while (top) pushdown(stk[top--]);
    while (!isroot(u))
    {
    if (!isroot(fa[u]))
    {
        if (which(u)==which(fa[u])) rotate(fa[u]);
        else rotate(u);
    }
    rotate(u);
    }
}

void access(int u)
{
    int v=0;
    while (u)
    {
    splay(u);
    rs[u]=v;
    v=u;
    u=fa[u];
    }
}

void makeroot(int u)
{
    access(u);
    splay(u);
    rev[u]^=1;
}

void link(int u,int v)
{
    makeroot(v);
    fa[v]=u;
}

void cut(int u,int v)
{
    makeroot(u);
    access(v);
    splay(v);
    ls[v]=fa[u]=0;
}

int query(int x)
{
    makeroot(n+1);
    access(x);
    splay(x);
    return sze[ls[x]];
}

int main()
{
    scanf("%d",&n);
    for (int i=1,x;i<=n;i++)
    {
    scanf("%d",&x);
    a[i]=(i+x<=n)?i+x:n+1;
    fa[i]=a[i];
    sze[i]=1;
    }
    sze[n+1]=1;
    scanf("%d",&m);
    while (m--)
    {
    int op,x,y;
    scanf("%d%d",&op,&x);
    ++x;
    if (op==1)
        printf("%d\n",query(x));
    else
    {
        scanf("%d",&y);
        cut(x,a[x]);
        a[x]=(x+y<=n)?x+y:n+1;
        link(x,a[x]);
    }
    }
    return 0;
}

以上是关于[bzoj] 2002 弹飞绵羊 || LCT的主要内容,如果未能解决你的问题,请参考以下文章

[bzoj2002][Hnoi2010]Bounce弹飞绵羊_LCT

bzoj 2002 : [Hnoi2010]Bounce 弹飞绵羊 (LCT)

[BZOJ 2002] 弹飞绵羊 LCT

[HNOI2010][BZOJ2002] 弹飞绵羊 - LCT

[bzoj] 2002 弹飞绵羊 || LCT

bzoj2002: [Hnoi2010]Bounce 弹飞绵羊 lct