• AC日记——文艺平衡树 洛谷 P3391


    文艺平衡树

    思路:

      splay翻转操作模板;

      虚拟最左最右端点,然后每次都把l翻转到root,r+2翻转到root的右节点;

      然后在r+2的左节点上打标记;

      标记需要在旋转,rank,print时下放;

      建树需要用完全平衡二叉树;

    来,上代码:

    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    
    using namespace std;
    
    #define maxn 100005
    
    struct TreeNodeType {
        int key,opi,size,ch[2],flag;
    };
    struct TreeNodeType tree[maxn];
    
    int n,m,root,ans[maxn],tot;
    
    inline void in(int &now)
    {
        register char Cget=getchar();now=0;
        while(Cget>'9'||Cget<'0') Cget=getchar();
        while(Cget>='0'&&Cget<='9')
        {
            now=now*10+Cget-'0';
            Cget=getchar();
        }
    }
    
    inline void updata(int now)
    {
        tree[now].size=1;
        if(tree[now].ch[0]) tree[now].size+=tree[tree[now].ch[0]].size;
        if(tree[now].ch[1]) tree[now].size+=tree[tree[now].ch[1]].size;
    }
    
    inline void down(int now)
    {
        tree[now].flag=0;
        swap(tree[now].ch[0],tree[now].ch[1]);
        if(tree[now].ch[0]) tree[tree[now].ch[0]].flag^=1;
        if(tree[now].ch[1]) tree[tree[now].ch[1]].flag^=1;
    }
    
    inline int getson(int now)
    {
        return tree[tree[now].opi].ch[1]==now;
    }
    
    void rotate(int now)
    {
        int opi=tree[now].opi,fopi=tree[opi].opi,pos=getson(now);
        if(tree[opi].flag&&opi) down(opi);
        if(tree[now].flag&&now) down(now);
        tree[opi].ch[pos]=tree[now].ch[!pos];
        tree[tree[now].ch[!pos]].opi=opi;
        tree[now].ch[!pos]=opi;
        tree[opi].opi=now;
        tree[now].opi=fopi;
        if(fopi) tree[fopi].ch[tree[fopi].ch[1]==opi]=now;
        updata(opi),updata(now);
    }
    
    inline void splay(int now,int to)
    {
        for(int opi;(opi=tree[now].opi)!=to;rotate(now))
        {
            if(tree[opi].opi!=to) rotate(getson(now)==getson(opi)?opi:now);
        }
        if(!to) root=now;
    }
    
    int rank_(int x)
    {
        int now=root;
        while(1)
        {
            if(tree[now].flag) down(now);
            if(tree[tree[now].ch[0]].size>=x) now=tree[now].ch[0];
            else
            {
                x-=tree[tree[now].ch[0]].size+1;
                if(!x) return now;
                now=tree[now].ch[1];
            }
        }
    }
    
    void print(int now)
    {
        if(tree[now].flag) down(now);
        if(tree[now].ch[0]) print(tree[now].ch[0]);
        ans[++tot]=tree[now].key;
        if(tree[now].ch[1]) print(tree[now].ch[1]);
    }
    
    int build(int l,int r,int opi)
    {
        int now=(l+r)>>1;
        tree[now].opi=opi;
        tree[now].key=ans[now];
        if(now>l) tree[now].ch[0]=build(l,now-1,now);
        if(now<r) tree[now].ch[1]=build(now+1,r,now);
        updata(now);return now;
    }
    
    int main()
    {
        in(n),in(m),root=1;
        for(int i=1;i<=n+2;i++) ans[i]=i-1;
        root=build(1,n+2,0);
        int l,r;
        while(m--)
        {
            in(l),in(r);
            l,r+=2;
            int x=rank_(l),y=rank_(r);
            splay(x,0);
            splay(y,x);
            tree[tree[tree[root].ch[1]].ch[0]].flag^=1;
        }
        print(root);
        for(int i=1;i<=n;i++) printf("%d ",ans[i+1]);
        return 0;
    }
  • 相关阅读:
    Jmeter之Web测试(一)
    Appium 提高脚本复用、可配置性
    Appium 解决中文输入问题
    Appium Python Driver Api
    Appium Android 屏幕滑动
    Android logcat使用
    android adb:电池与电量
    Loadrunner测试json接口
    python输出1到100之和的几种方法
    python 随机生成用户名、密码、手机号码
  • 原文地址:https://www.cnblogs.com/IUUUUUUUskyyy/p/6730477.html
Copyright © 2020-2023  润新知