[LCT]luogu P3203 弹飞绵羊

https://www.luogu.org/problem/P3203

 

分析

还有个模板不想写题解了,反正这题也差不多是个模板

可以将一个点往后跳跃到的点连起来,跳出去的连到根节点+1,这就是棵树

 

要求支持删边连边和求根节点到这里的深度?LCT完全可以胜任

就是个板子,深度不用特别思考,Split直接提出来的是链,求Splay大小即可

 

#include <iostream>
#include <cstdio>
using namespace std;
const int N=2e5+10; 
struct Node {
    int f,c[2],s,rev;
}t[N];
int stk[N],top,v[N];
int n,m;

bool Witch(int x) {return x==t[t[x].f].c[1];}

bool Check_Root(int x) {return t[t[x].f].c[0]==x||t[t[x].f].c[1]==x;}

void Reverse(int x) {swap(t[x].c[0],t[x].c[1]),t[x].rev^=1;}

void Pushdown(int x) {if (t[x].rev) Reverse(t[x].c[0]),Reverse(t[x].c[1]),t[x].rev=0;}

void Update(int x) {t[x].s=t[t[x].c[0]].s+t[t[x].c[1]].s+1;}

void Rotate(int x) {
    int f=t[x].f,gf=t[f].f,lr=Witch(x);
    t[x].f=gf;if (Check_Root(f)) t[gf].c[Witch(f)]=x;
    t[f].c[lr]=t[x].c[lr^1];if (t[f].c[lr]) t[t[f].c[lr]].f=f;
    t[t[x].c[lr^1]=f].f=x;
    Update(f);
}

void Splay(int x) {
    int y=x;stk[++top]=y;
    for (;Check_Root(y);y=t[y].f) stk[++top]=t[y].f;
    for (;top;Pushdown(stk[top--]));
    for (;Check_Root(x);Rotate(x))
        if (Check_Root(t[x].f)) Rotate(Witch(x)!=Witch(t[x].f)?x:t[x].f);
    Update(x);
}

void Access(int x) {for (int y=0;x;x=t[y=x].f) Splay(x),t[x].c[1]=y,Update(x);}

void Make_Root(int x) {Access(x);Splay(x);Reverse(x);}

int Get_Root(int x) {
    Make_Root(x);Splay(x);
    while (t[x].c[0]) x=t[x].c[0],Pushdown(x);
    Splay(x);return x;
}

void Split(int x,int y) {Make_Root(x);Access(y);Splay(y);}

void Link(int x,int y) {Make_Root(x);if (Get_Root(y)!=x) t[x].f=y;}

void Cut(int x,int y) {Split(x,y);if (t[y].c[0]==x) t[x].f=t[y].c[0]=0,Update(y);}

int main() {
    scanf("%d",&n);
    for (int i=1,x;i<=n;i++) {
        scanf("%d",&x);
        v[i]=min(i+x,n+1);
        Link(i,v[i]);
    }
    scanf("%d",&m);
    for (int i=1;i<=m;i++) {
        int order,x,y;
        scanf("%d",&order);
        switch (order) {
            case 1:{
                scanf("%d",&x);x++;
                Split(x,n+1);printf("%d\n",t[n+1].s-1);
                break;
            }
            case 2:{
                scanf("%d%d",&x,&y);x++;
                if (v[x]==min(x+y,n+1)) continue;
                Cut(x,v[x]);Link(x,v[x]=min(x+y,n+1));
                break;
            }
        }
    }
}
View Code

 

posted @ 2019-08-09 07:39  Vagari  阅读(138)  评论(0编辑  收藏  举报