洛谷-1801 黑匣子_NOI导刊2010提高(06)

题目描述
Black Box是一种原始的数据库。它可以储存一个整数数组,还有一个特别的变量i。最开始的时候Black Box是空的.而i等于0。这个Black Box要处理一串命令。
命令只有两种:
ADD(x):把x元素放进BlackBox;
GET:i加1,然后输出Blackhox中第i小的数。
记住:第i小的数,就是Black Box里的数的按从小到大的顺序排序后的第i个元素。
现在要求找出对于给定的命令串的最好的处理方法。ADD和GET命令分别最多200000个。现在用两个整数数组来表示命令串:
1.A(1),A(2),…A(M):一串将要被放进Black Box的元素。每个数都是绝对值不超过2000000000的整数,M$200000。例如上面的例子就是A=(3,1,一4,2,8,-1000,2)。
2.u(1),u(2),…u(N):表示第u(j)个元素被放进了Black Box里后就出现一个GET命令。例如上面的例子中u=(l,2,6,6)。输入数据不用判错。
输入输出格式
输入格式:
第一行,两个整数,M,N。
第二行,M个整数,表示A(l)
……A(M)。
第三行,N个整数,表示u(l)
…u(N)。
输出格式:
输出Black Box根据命令串所得出的输出串,一个数字一行。

输入输出样例
输入样例#1:
7 4
3 1 -4 2 8 -1000 2
1 2 6 6

输出样例#1:
3
3
1
2

说明
对于30%的数据,M≤10000;
对于50%的数据,M≤100000:
对于100%的数据,M≤200000。

解释:直接上splay模板,第K小的话模板都有直接调用就好了

//splay
#include<stdio.h>
using namespace std;
const int MAXL=200005;
const int INF=2147480000;
class Splay{
    #define root e[0].ch[1]   //该树的根节点
    private:
        class node{
            public:
                int v,father;//节点值,父级节点 
                int ch[2];//左孩子=0,右孩子=1
                int sum;//自己+自己下级有多少节点。在根节点为1。
                int recy;//记录自己被重复了几次
        };
        node e[MAXL];//Splay树主体
        int n,points;//使用存储数,元素数
        inline void update(int x){
            e[x].sum=e[e[x].ch[0]].sum+e[e[x].ch[1]].sum+e[x].recy;
        }
        int identify(int x){
            return e[e[x].father].ch[0]==x?0:1;
        }
        inline void connect(int x,int f,int son){
            e[x].father=f;
            e[f].ch[son]=x;
        }//作用:使得x的father=f,f的son=x.
        inline void rotate(int x){
            int y=e[x].father;
            int mroot=e[y].father;
            int mrootson=identify(y);
            int yson=identify(x);
            int B=e[x].ch[yson^1];
            connect(B,y,yson);connect(y,x,(yson^1));connect(x,mroot,mrootson);
            update(y);update(x);
        }
        inline void splay(int at,int to){
            to=e[to].father;
            while(e[at].father!=to){
                int up=e[at].father;
                if(e[up].father==to) rotate(at);
                else if(identify(up)==identify(at)){
                    rotate(up);
                    rotate(at);
                }
                else{
                    rotate(at);
                    rotate(at);
                }
            }
        }
        inline int crepoint(int v,int father){
            n++;
            e[n].v=v;
            e[n].father=father;
            e[n].sum=e[n].recy=1;
            return n;
        }
        inline void destroy(int x){
            e[x].v=e[x].ch[0]=e[x].ch[1]=e[x].sum=e[x].father=e[x].recy=0;
            if(x==n) n--;//最大限度优化
        }
    public:
        inline int getroot(){return root;}
        inline int find(int v){
            int now=root;
            while(true){
                if(e[now].v==v){
                    splay(now,root);
                    return now;
                }
                int next=v<e[now].v?0:1;
                if(!e[now].ch[next]) return 0;
                now=e[now].ch[next];
            }
        }
        inline int build(int v){
            points++;
            if(n==0){
                root=1;
                crepoint(v,0);
            }
            else{
                int now=root;
                while(true){
                    e[now].sum++;//自己的下级肯定增加了一个节点 
                    if(v==e[now].v){
                        e[now].recy++;
                        return now;
                    }
                    int next=v<e[now].v?0:1;
                    if(!e[now].ch[next]){
                        crepoint(v,now);
                        e[now].ch[next]=n;
                        return n;
                    }
                    now=e[now].ch[next];
                }
            }
            return 0;
        }
        void push(int v){
            int add=build(v);
            splay(add,root);
        }
        inline void pop(int v){
            int deal=find(v);
            if(!deal) return;
            points--;
            if(e[deal].recy>1){
                e[deal].recy--;
                e[deal].sum--;
                return;
            }
            if(!e[deal].ch[0]){
                root=e[deal].ch[1];
                e[root].father=0;
            }
            else{
                int lef=e[deal].ch[0];
                while(e[lef].ch[1]) lef=e[lef].ch[1];
                splay(lef,e[deal].ch[0]);
                int rig=e[deal].ch[1];
                connect(rig,lef,1);connect(lef,0,1);
                update(lef);
            }
            destroy(deal);
        }
        inline int rank(int v){
            int ans=0,now=root;
            while(true){
                if(e[now].v==v) return ans+e[e[now].ch[0]].sum+1;
                if(now==0) return 0;
                if(v<e[now].v) now=e[now].ch[0];
                else
                {
                    ans=ans+e[e[now].ch[0]].sum+e[now].recy;
                    now=e[now].ch[1];
                }
            }
            if(now) splay(now,root);
            return 0;
        }
        inline int atrank(int x){
            if(x>points) return -INF;
            int now=root;
            while(true){
                int minused=e[now].sum-e[e[now].ch[1]].sum;
                if(x>e[e[now].ch[0]].sum&&x<=minused) break;
                if(x<minused) now=e[now].ch[0];
                else
                {
                    x=x-minused;
                    now=e[now].ch[1];
                }
            }
            splay(now,root);
            return e[now].v;
        }
        inline int upper(int v){
            int now=root;
            int result=INF;
            while(now){
                if(e[now].v>v&&e[now].v<result) result=e[now].v;
                if(v<e[now].v) now=e[now].ch[0];
                else now=e[now].ch[1];
            }
            return result;
        }
        inline int lower(int v){
            int now=root;
            int result=-INF;
            while(now){
                if(e[now].v<v&&e[now].v>result) result=e[now].v;
                if(v>e[now].v) now=e[now].ch[1];
                else now=e[now].ch[0];
            }
            return result;
        }
    #undef root
};template <class T>
inline bool scan_d(T &ret) 
{
    char c; 
    int sgn;
    if (c = getchar(), c == EOF) 
    {
        return 0; //EOF 
    }
    while (c != '-' && (c < '0' || c > '9')) 
    {
        c = getchar(); 
    }
    sgn = (c == '-') ? -1 : 1;
    ret = (c == '-') ? 0 : (c - '0'); 
    while (c = getchar(), c >= '0' && c <= '9') 
    {
        ret = ret * 10 + (c - '0'); 
    }
    ret *= sgn;
    return 1;
}
template <class T>
void Out(T a) 
{   //  输出外挂  
    if (a < 0) 
    {
        putchar('-');
        a = -a;
    }  
    if (a >= 10)
    {
       Out(a / 10);  
    }
    putchar(a % 10 + '0');  
}  

Splay F;
int n=0,m=0;
int a[MAXL]={0},b[MAXL]={0};
int main(){
    scan_d(n);scan_d(m);
    F.push(INF);F.push(-INF);
    for(int i=1;i<=n;i++) scan_d(a[i]);
    for(int i=1;i<=m;i++) scan_d(b[i]);
	int A=0,B=0;
	for(int i=1;i<=m;i++){
		while(A<b[i]) F.push(a[++A]);
		Out(F.atrank(++B+1));putchar('\n');
	}
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值