zoukankan      html  css  js  c++  java
  • Luogu 3369 / BZOJ 3224

    题目链接:

    https://www.lydsy.com/JudgeOnline/problem.php?id=3224

    https://www.luogu.org/problemnew/show/P3369

    Description

    您需要写一种数据结构(可参考题目标题),来维护一些数,其中需要提供以下操作:
    1. 插入x数
    2. 删除x数(若有多个相同的数,因只删除一个)
    3. 查询x数的排名(若有多个相同的数,因输出最小的排名)
    4. 查询排名为x的数
    5. 求x的前驱(前驱定义为小于x,且最大的数)
    6. 求x的后继(后继定义为大于x,且最小的数)

    Input

    第一行为n,表示操作的个数,下面n行每行有两个数opt和x,opt表示操作的序号(1<=opt<=6)

    Output

    对于操作3,4,5,6每行输出一个数,表示对应答案

    Sample Input

    10

    1 106465

    4 1

    1 317721

    1 460929

    1 644985

    1 84185

    1 89851

    6 81968

    1 492737

    5 493598

    Sample Output

    106465

    84185

    492737

    HINT

    1.n的数据范围:n<=100000

    2.每个数的数据范围:[-2e9,2e9]

    关于替罪羊树:

    替罪羊树的主要思想就是将不平衡的树压成一个序列,然后暴力重构成一颗平衡的树。

    这里的平衡指的是:对于某个 $0.5 le alpha le 1$ 满足 $size( ls(x) ) le alpha cdot size(x)$ 并且 $size( rs(x) ) le alpha cdot size(x)$。一般 $alpha$ 取 $0.7 sim 0.8$。

    更加详细的解释和模板请参考替罪羊树(重量平衡树)入门

    AC代码:

    #include<bits/stdc++.h>
    using namespace std;
    
    const int maxn=1e5+10;
    const double alpha=0.8;
    struct Node
    {
        Node* ch[2]; //左右子节点
        int key,siz,cov; //key是值,siz是以该节点为根的树的存在的节点数,cover是所有节点数量
        bool ext;
        void pushup() { //更新函数
            siz = ch[0]->siz + ch[1]->siz + ext;
            cov = ch[0]->cov + ch[1]->cov + 1;
        }
        inline bool isbad() { //判断是否要重构
            return alpha*cov+5 < max(ch[0]->cov,ch[1]->cov);
        }
    };
    struct ScapegoatTree
    {
    protected:
        Node mem[maxn]; //内存池
        Node *tail,*null,*root; //tail为指向内存池元素的指针
        Node *bak[maxn]; int baksz; //内存回收池
    
        Node* newnode(int key)
        {
            Node* p=baksz?bak[--baksz]:tail++;
            p->ch[0] = p->ch[1] = null;
            p->siz = p->cov= p->ext = 1;
            p->key = key;
            return p;
        }
    
        void travel(vector<Node*>& v,Node* p) //中序遍历将一棵树转化成序列
        {
            if(p==null) return;
            travel(v,p->ch[0]);
            if(p->ext) v.push_back(p);
            else bak[baksz++]=p;
            travel(v,p->ch[1]);
        }
    
        Node* build(vector<Node*>& v,int l,int r)
        {
            if(l>=r) return null;
            int mid=(l+r)>>1;
            Node *p=v[mid];
            p->ch[0] = build(v,l,mid);
            p->ch[1] = build(v,mid+1,r);
            p->pushup();
            return p;
        }
    
        vector<Node*> cur;
        void rebuild(Node*& p)
        {
            cur.clear();
            travel(cur,p);
            p=build(cur,0,cur.size());
        }
    
        Node** insert(Node*& p,int val)
        {
            if(p==null)
            {
                p=newnode(val);
                return &null;
            }
            p->siz++, p->cov++;
            Node** res=insert(p->ch[val>=p->key],val);
            if(p->isbad()) res=&p;
            return res;
        }
    
        void erase(Node*& p,int k)
        {
            p->siz--; //维护siz
            int offset = p->ch[0]->siz + p->ext; //计算左子树的存在的节点总数
            if(p->ext && k==offset) p->ext=0;
            else
            {
                if(k<=offset) erase(p->ch[0],k);
                else erase(p->ch[1],k-offset);
            }
        }
    
    public:
        void init()
        {
            tail=mem;
            null=tail++;
            null->ch[0] = null->ch[1] = null;
            null->key = 0;
            null->siz = null->cov = null->ext = 0;
            root=null; //初始化根节点
            baksz=0; //清空栈
        }
        ScapegoatTree() {
            init();
        }
    
        void insert(int val)
        {
            Node** res=insert(root,val);
            if(*res!=null) rebuild(*res);
        }
    
        int getrank(int val)
        {
            Node *p=root;
            int res=1;
            while(p!=null)
            {
                if(val <= p->key) p=p->ch[0];
                else
                {
                    res += p->ch[0]->siz + p->ext;
                    p = p->ch[1];
                }
            }
            return res;
        }
    
        int getkth(int k)
        {
            Node *p=root;
            while(p!=null)
            {
                if(p->ch[0]->siz+1==k && p->ext) return p->key;
                if(k <= p->ch[0]->siz) p=p->ch[0];
                else k-=p->ch[0]->siz + p->ext, p=p->ch[1];
            }
        }
    
        void delval(int val)
        {
            erase(root,getrank(val));
            if(root->siz < alpha * root->cov) rebuild(root);
        }
    
        void delkth(int k)
        {
            erase(root,k);
            if(root->siz < alpha * root->cov) rebuild(root);
        }
    }st;
    
    int main()
    {
        int n,opt,x;
        scanf("%d",&n);
        while(n--)
        {
            scanf("%d%d",&opt,&x);
            if(opt==1) st.insert(x);
            if(opt==2) st.delval(x);
            if(opt==3) printf("%d
    ",st.getrank(x));
            if(opt==4) printf("%d
    ",st.getkth(x));
            if(opt==5) printf("%d
    ",st.getkth(st.getrank(x)-1));
            if(opt==6) printf("%d
    ",st.getkth(st.getrank(x+1)));
        }
    }
  • 相关阅读:
    【转】嵌入式程序员应该知道的16个问题
    GetMemory()函数
    Some good questions
    [转]永远做一个有计划的人
    内存分配管理
    c语言面试题(感觉比较好的题目)
    const char*, char const*, char*const的区别
    《论语》《中庸》《大学》经典语录
    洗脑
    python基础之函数参数,名称空间,以及函数嵌套
  • 原文地址:https://www.cnblogs.com/dilthey/p/10051787.html
Copyright © 2011-2022 走看看