zoukankan      html  css  js  c++  java
  • P3203 [HNOI2010]弹飞绵羊(LCT)

    弹飞绵羊

    题目传送门

    解题思路

    LCT。

    将每个节点的权值设为(1),连接(i)(i+ki),被弹飞就连上(n),维护权值和(sum[])。从(j)弹飞需要的次数就是(split(j,n))后,(sum[i]-1)的值。修改弹力系数,即为断开(i)和旧的(i+ki)的连接,然后连上(i)和新的(i+ki)

    为了方便,以下代码把下标都加一了,即原编号变为(1-n),弹飞设为(n+1)

    代码如下

    #include <bits/stdc++.h>
    
    using namespace std;
    
    const int N = 200005;
    
    int fa[N], ch[N][2], siz[N], rev[N], sta[N], v[N];
    
    inline bool get(int x)
    {
        return ch[fa[x]][1] == x;
    }
    
    inline bool isroot(int x)
    {
        return (!fa[x] || ch[fa[x]][1] != x && ch[fa[x]][0] != x);
    }
    
    inline void push_up(int x)
    {
        siz[x] = siz[ch[x][1]] + siz[ch[x][0]] + 1;
    }
    
    inline void rotate(int x)
    {
        int y = fa[x], z = fa[y];
        bool u = get(x);
        ch[y][u] = ch[x][u^1], fa[ch[x][u^1]] = y;
        if(!isroot(y))
            ch[z][get(y)] = x;
        fa[x] = z;
        ch[x][u^1] = y, fa[y] = x;
        push_up(y), push_up(x);
    }
    
    inline void pushr(int x)
    {
        swap(ch[x][1], ch[x][0]);
        rev[x] ^= 1;
    }
    
    inline void push_down(int x)
    {
        if(rev[x]){
            pushr(ch[x][0]), pushr(ch[x][1]);
            rev[x] = 0;
        }
    }
    
    inline void splay(int x)
    {
        int pos = 0;
        sta[++pos] = x;
        for(int i = x; !isroot(i); i = fa[i])
            sta[++pos] = fa[i];
        while(pos)
            push_down(sta[pos--]);
        while(!isroot(x)){
            int y = fa[x];
            if(!isroot(y))
                get(x) == get(y) ? rotate(y): rotate(x);
            rotate(x);
        }
    }
    
    inline void access(int x)
    {
        for(int y = 0; x; y = x, x = fa[x])
            splay(x), ch[x][1] = y, push_up(x);
    }
    
    inline void make_root(int x)
    {
        access(x); splay(x);
        pushr(x);
    }
    
    inline void split(int x, int y)
    {
        make_root(x);
        access(y);splay(y);
    }
    
    inline void link(int x, int y)
    {
        make_root(x);
        fa[x] = y;
    }
    
    inline void cut(int x, int y)
    {
        split(x, y);
        fa[x] = ch[y][0] = 0;
        push_up(y);
    }
    
    int main()
    {
        int n;
        scanf("%d", &n);
        for(int i = 1; i <= n; i ++){
            scanf("%d", &v[i]);
            siz[i] = 1;
        }
        siz[n + 1] = 1;
        for(int i = 1; i <= n; i ++){
            if(i + v[i] <= n)
                link(i, i + v[i]);
            else
                link(i, n + 1);
        }
        int m;
        scanf("%d", &m);
        for(int i = 1; i <= m; i ++){
            int opt, x;
            scanf("%d%d", &opt, &x);
            ++x;
            if(opt == 1){
                split(n + 1, x);
                printf("%d
    ", siz[x] - 1);
            }
            else {
                int k;
                scanf("%d", &k);
                if(x + v[x] <= n)
                    cut(x, x + v[x]);
                else
                    cut(x, n + 1);
                if(x + k <= n)
                    link(x, x + k);
                else
                    link(x, n + 1);
                v[x] = k;
            }
        }
        return 0;
    }
    
  • 相关阅读:
    软件测试——C#判断密码是否符合要求
    软件测试——C#判断闰年的form小程序
    初识JUnit
    软件测试的方法一共有几种
    多个异步请求调用一个回调函数
    单元测试、集成测试、系统测试总结
    软件测试同行评审流程
    白盒测试总结
    黑盒测试总结
    闰年测试
  • 原文地址:https://www.cnblogs.com/whisperlzw/p/11404163.html
Copyright © 2011-2022 走看看