zoukankan      html  css  js  c++  java
  • 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
    ",x,y);
        makeroot(x);
        fa[x]=y;
    //  update(x);update(y);
    }
     
    void cut(int x,int y)
    {
    //  printf("cut %d %d
    ",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
    ",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;
            }
        }
    }
    

      

  • 相关阅读:
    非循环单链表节点的操作
    链表每一个节点的数据类型该如何表示
    链表的定义、确定一个链表需要几个参数?
    typedef的用法
    连续存储数组的算法(包含数组倒置、冒泡排序……)
    跨函数使用内存案例
    malloc()动态分配内存概述
    结构体
    指针和数组
    C#基础知识之dnSpy反编译
  • 原文地址:https://www.cnblogs.com/SfailSth/p/6195075.html
Copyright © 2011-2022 走看看