• bzoj 1503 郁闷的出纳员


    treap裸题...

    还是要写一下,毕竟是第一个成功用treap维护的题,做个纪念吧

    这题的中心思想其实很简单,就是插入+删除+查询排名为x的数

    但是重点是,全体的标记怎么处理?

    首先有一个很显然的思想,就是在修改全体的时候,我们不去修改全体的值,而是去修改界限

    但这样做有一个很显然的问题:界限修改了,新来的值怎么办?

    所以我们对这个思想进行一个优化,我们维护两个值,一个是minv,一个是lazy(仿线段树中懒惰标记),保证在任何时刻,minv+lazy=初始的minv

    这样一来,每次新来一个值,我都把它和minv+lazy比较再考虑是否插入即可

    而且在插入时,我们应该插入的时num-lazy,这样才能保证,对于treap中任何一个值,num+lazy=该时间下的真实值

    剩下的就很简单了,由于数据范围中删除操作的次数很有限,所以我们可以暴力删除(当然也可以考虑整树删除,但这就过于麻烦了)

    贴代码:

    #include <cstdio>
    #include <cmath>
    #include <cstring>
    #include <cstdlib>
    #include <iostream>
    #include <algorithm>
    #include <queue>
    #include <stack>
    #include <ctime>
    #define ls tree[rt].lson
    #define rs tree[rt].rson
    using namespace std;
    struct Treap
    {
        int lson;
        int rson;
        int huge;
        int rank;
        int val;
        int same;
    }tree[100005];
    int n,minv,lazy;
    char s[2];
    int tot=0;
    int rot=0;
    void update(int rt)
    {
        tree[rt].huge=tree[ls].huge+tree[rs].huge+tree[rt].same;
    }
    void lturn(int &rt)
    {
        int temp=rs;
        rs=tree[rs].lson;
        tree[temp].lson=rt;
        tree[temp].huge=tree[rt].huge;
        update(rt);
        rt=temp;
    }
    void rturn(int &rt)
    {
        int temp=ls;
        ls=tree[ls].rson;
        tree[temp].rson=rt;
        tree[temp].huge=tree[rt].huge;
        update(rt);
        rt=temp;
    }
    void ins(int &rt,int v)
    {
        if(!rt)
        {
            rt=++tot;
            tree[rt].huge=1;
            tree[rt].same=1;
            tree[rt].val=v;
            tree[rt].rank=rand();
            return;
        }
        tree[rt].huge++;
        if(v==tree[rt].val)
        {
            tree[rt].same++;
            return;
        }else if(v<tree[rt].val)
        {
            ins(ls,v);
            if(tree[ls].rank<tree[rt].rank)
            {
                rturn(rt);
            }
        }else
        {
            ins(rs,v);
            if(tree[rs].rank<tree[rt].rank)
            {
                lturn(rt);
            }
        }
    }
    void del(int &rt,int v)
    {
        if(!rt)
        {
            return;
        }
        if(tree[rt].val==v)
        {
            if(tree[rt].same>1)
            {
                tree[rt].huge--;
                tree[rt].same--;
                return;
            }else
            {
                if(ls*rs==0)
                {
                    rt=ls+rs;
                    return;
                }else if(tree[ls].rank<tree[rs].rank)
                {
                    rturn(rt);
                    del(rt,v);
                }else
                {
                    lturn(rt);
                    del(rt,v);
                }
                return;
            }
        }
        tree[rt].huge--;
        if(tree[rt].val>v)
        {
            del(ls,v);
        }else
        {
            del(rs,v);
        }
    }
    int ans=0;
    bool flag=0;
    void query_pro(int rt,int v)//求前驱 
    {
        if(rt==0)
        {
            return;
        }
        if(tree[rt].val<v)
        {
            ans=tree[rt].val;
            flag=1;
            query_pro(rs,v);
        }else
        {
            query_pro(ls,v);
        }
    }
    int query_num(int rt,int v)//查询排名为x的数 
    {
        if(rt==0)
        {
            return 0;
        }
        if(tree[rs].huge<v&&tree[rt].same+tree[rs].huge>=v)
        {
            return tree[rt].val;
        }else if(tree[rs].huge>=v)
        {
            return query_num(rs,v);
        }else
        {
            return query_num(ls,v-tree[rs].huge-tree[rt].same);
        }
    }
    inline int read()
    {
        int f=1,x=0;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 main()
    {
        n=read(),minv=read();
        int cnt=0;
        int cot=0;
        for(int i=1;i<=n;i++)
        {
            scanf("%s",s);
            if(s[0]=='I')
            {
                int x=read();
                if(x-lazy<minv)
                {
                    continue;
                }else
                {
                    cot++;
                    ins(rot,x-lazy);
                }
            }else if(s[0]=='A')
            {
                int x=read();
                lazy+=x;
                minv-=x;
            }else if(s[0]=='S')
            {
                int x=read();
                lazy-=x;
                minv+=x;
                ans=0;
                flag=0;
                query_pro(rot,minv);
                while(flag)
                {
                    del(rot,ans);
                    ans=0;
                    flag=0;
                    cot--;
                    cnt++;
                    query_pro(rot,minv);
                }
            }else
            {
                int x=read();
                if(x>cot)
                {
                    printf("-1
    ");
                    continue;
                }else
                {
                    printf("%d
    ",query_num(rot,x)+lazy);
                }
            }
        }
        printf("%d
    ",cnt);
        return 0;
    }
  • 相关阅读:
    基础
    树梅派线程
    超声波
    电脑版微信双开多开
    子类能不能重写父类的构造方法
    window8taskost.exe一直占用cpu
    windows下rocketmq安装
    spring循环依赖问题
    线程池的种类
    并行和并发有什么区别?
  • 原文地址:https://www.cnblogs.com/zhangleo/p/9650838.html
Copyright © 2020-2023  润新知