BZOJ 2002 [Hnoi2010]Bounce 弹飞绵羊 ——Link-Cut Tree

【题目分析】

    以前用分块的方法做过这道题目,现在再用LCT水一边,发现思路确实巧妙。

    每次弹射,可以看作在一条边上走了过去,而且很重要的性质,每一个点的出边只有一条。

    那么就很容易知道,可以用LCT维护连通性,然后把n+1这个虚点当作根,把起点旋转上去,然后n+1的深度就是结果的值。

    更进一步,由于偏爱路径只是起点到n+1,深度又改为了子树大小size的查询。

    均摊复杂度NlogN

【代码】

#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
 
#include <set>
#include <map>
#include <string>
#include <algorithm>
#include <vector>
#include <iostream>
#include <queue>
 
using namespace std;
 
#define maxn 1000005
#define inf (0x3f3f3f3f)
 
int read()
{
    int x=0,f=1; 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 fa[maxn],ch[maxn][2],siz[maxn],rev[maxn],top=0,sta[maxn];
 
bool isroot(int x)
{
    return ch[fa[x]][0]!=x&&ch[fa[x]][1]!=x;
}
 
void update(int x)
{
    siz[x]=siz[ch[x][0]]+siz[ch[x][1]]+1;
}
 
void pushdown(int x)
{
    if (rev[x])
    {
        rev[x]^=1;
        rev[ch[x][0]]^=1;
        rev[ch[x][1]]^=1;
        swap(ch[x][0],ch[x][1]);
    }
}
 
void rot(int x)
{
    int y=fa[x],z=fa[y],l,r;
    if (ch[y][0]==x) l=0; else l=1;
    r=l^1;
    if (!isroot(y))
    {
        if (ch[z][0]==y) ch[z][0]=x;
        else ch[z][1]=x;
    }
    fa[x]=z; fa[y]=x; fa[ch[x][r]]=y;
    ch[y][l]=ch[x][r]; ch[x][r]=y;
    update(y); update(x);
}
 
void splay(int x)
{
    int top=0; sta[++top]=x;
    for (int i=x;!isroot(i);i=fa[i]) sta[++top]=fa[i];
    while (top) pushdown(sta[top--]);
    while (!isroot(x))
    {
        int y=fa[x],z=fa[y];
        if (!isroot(y))
        {
            if (ch[y][0]==x^ch[z][0]==y) rot(x);
            else rot(y);
        }
        rot(x);
    }
}
 
void access(int x)
{
    for (int t=0;x;t=x,x=fa[x])
    {
        splay(x);
        ch[x][1]=t;
        update(x);
    }
}
 
void makeroot(int x)
{
    access(x);
    splay(x);
    rev[x]^=1;
}
 
int find(int x)
{
    access(x);
    splay(x);
    while (ch[x][0]) x=ch[x][0];
    return x;
}
 
void link(int x,int y)
{
//  printf("link %d %d\n",x,y);
    makeroot(x);
    fa[x]=y;
//  update(x);update(y);
}
 
void cut(int x,int y)
{
//  printf("cut %d %d\n",x,y);  
    makeroot(x);
    access(y);
    splay(y);
    ch[y][0]=fa[x]=0;
//  update(x);update(y);
}
 
int m,n,a[maxn];
 
int main()
{
    n=read(); for (int i=1;i<=n;++i) a[i]=read(),link(i,min(n+1,a[i]+i));
    m=read();
    while (m--)
    {
        int opt,x,y;
        opt=read();x=read(); x++;
        switch(opt)
        {
            case 1:
//              x=read();x++;
                makeroot(n+1);
                access(x);
                splay(x);
                printf("%d\n",siz[x]-1);
                break;
            case 2:
//              x=read();x++;
                y=read();
                cut(x,min(n+1,a[x]+x));
                a[x]=y;
                link(x,min(n+1,a[x]+x));
            break;
        }
    }
}

  

posted @ 2016-12-18 17:41  SfailSth  阅读(53)  评论(0编辑  收藏