【POJ 1442 && 洛谷 P1801】黑匣子(替罪羊树做法)

Black Box

Time Limit: 1000MSMemory Limit: 10000K
Total Submissions: 13823Accepted: 5626

Description

Our Black Box represents a primitive database. It can save an integer array and has a special i variable. At the initial moment Black Box is empty and i equals 0. This Black Box processes a sequence of commands (transactions). There are two types of transactions:


ADD (x): put element x into Black Box;

GET: increase i by 1 and give an i-minimum out of all integers containing in the Black Box. Keep in mind that i-minimum is a number located at i-th place after Black Box elements sorting by non- descending.


Let us examine a possible sequence of 11 transactions:


Example 1

 

N Transaction i Black Box contents after transaction Answer

(elements are arranged by non-descending)

1 ADD(3) 0 3

2 GET 1 3 3

3 ADD(1) 1 1, 3

4 GET 2 1, 3 3

5 ADD(-4) 2 -4, 1, 3

6 ADD(2) 2 -4, 1, 2, 3

7 ADD(8) 2 -4, 1, 2, 3, 8

8 ADD(-1000) 2 -1000, -4, 1, 2, 3, 8

9 GET 3 -1000, -4, 1, 2, 3, 8 1

10 GET 4 -1000, -4, 1, 2, 3, 8 2

11 ADD(2) 4 -1000, -4, 1, 2, 2, 3, 8


It is required to work out an efficient algorithm which treats a given sequence of transactions. The maximum number of ADD and GET transactions: 30000 of each type.



Let us describe the sequence of transactions by two integer arrays:



1. A(1), A(2), …, A(M): a sequence of elements which are being included into Black Box. A values are integers not exceeding 2 000 000 000 by their absolute value, M <= 30000. For the Example we have A=(3, 1, -4, 2, 8, -1000, 2).


2. u(1), u(2), …, u(N): a sequence setting a number of elements which are being included into Black Box at the moment of first, second, … and N-transaction GET. For the Example we have u=(1, 2, 6, 6).


The Black Box algorithm supposes that natural number sequence u(1), u(2), …, u(N) is sorted in non-descending order, N <= M and for each p (1 <= p <= N) an inequality p <= u(p) <= M is valid. It follows from the fact that for the p-element of our u sequence we perform a GET transaction giving p-minimum number from our A(1), A(2), …, A(u(p)) sequence.



Input

Input contains (in given order): M, N, A(1), A(2), …, A(M), u(1), u(2), …, u(N). All numbers are divided by spaces and (or) carriage return characters.

Output

Write to the output Black Box answers sequence for a given sequence of transactions, one number each line.

Sample Input

7 4 
3 1 -4 2 8 -1000 2
1 2 6 6

Sample Output

3 
3
1
2

Source

题意

    有一些ADD和GET操作。n次ADD操作,每次往序列中加入一个数,由ADD操作可知序列长度为1-n时序列的组成。GET操作输入一个序列长度,第i个数 ai 表示你需要输出当前长度序列为 ai (即在第 ai 次ADD操作后)第i大的元素的值。给出的GET操作输入非降。

思路

    虽然这题好像一眼望上去就是splay,或者一些STL的奇技淫巧过这题,但我太菜了并不会splay这个东西,所以我就用上了不久前刚学到的替罪羊树,没想到还跑得挺快,在POJ上只用了94ms,因为这只是一道模板题,所以……好像也没什么好讲的..只是我刚开始记录下查询操作的时候用的是map里套vector来表示在这个ADD操作后是否有查询值,结果T掉了..然后我发现GET操作输入的序列是非降的。。于是只要在操作的时候记录上次已经查询完的位置在哪然后直接在那里往下找就行了。

Code

#pragma GCC optimize(3)
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdio>
#include<cctype>
#include<climits>
#include<cstdlib>
#include<cmath>
#include<map>
#include<stack>
#include<climits>
#include<vector>
using namespace std;
typedef long long ll;
bool Finish_read;
template<class T>inline void read(T &x){Finish_read=0;x=0;int f=1;char ch=getchar();while(!isdigit(ch)){if(ch=='-')f=-1;if(ch==EOF)return;ch=getchar();}while(isdigit(ch))x=x*10+ch-'0',ch=getchar();x*=f;Finish_read=1;}
template<class T>inline void print(T x){if(x/10!=0)print(x/10);putchar(x%10+'0');}
template<class T>inline void writeln(T x){if(x<0)putchar('-');x=abs(x);print(x);putchar('\n');}
template<class T>inline void write(T x){if(x<0)putchar('-');x=abs(x);print(x);}
/*================Header Template==============*/
struct ScapeGoatTree {
    static const int maxn=200010,oo=(1LL<<31)-1;
    static const double alpha=0.75;
    int cntx,root;
    struct TreeNode {
        int son[2];
        int fa;
        int siz;
        int num;
    }t[maxn];
    int treeid[maxn],cnt;
    inline bool balance(int id) {
        return (double)t[id].siz*alpha>=(double)t[t[id].son[0]].siz&&(double)t[id].siz*alpha>=(double)t[t[id].son[1]].siz;
    }
    inline void recycle(int id) {
        if(t[id].son[0])
            recycle(t[id].son[0]);
        treeid[++cnt]=id;
        if(t[id].son[1])
            recycle(t[id].son[1]);
    }
    inline int build(int l,int r) {
        if(l>r)
            return 0;
        int mid=(l+r)>>1,id=treeid[mid];
        t[t[id].son[0]=build(l,mid-1)].fa=id;
        t[t[id].son[1]=build(mid+1,r)].fa=id;
        t[id].siz=t[t[id].son[0]].siz+t[t[id].son[1]].siz+1;
        return id;
    }
    inline void rebuild(int id) {
        cnt=0;
        recycle(id);
        int fa=t[id].fa,child=t[t[id].fa].son[1]==id,current=build(1,cnt);
        t[t[fa].son[child]=current].fa=fa;
        if(id==root)
            root=current;
    }
    inline void insert(int x) {
        int now=root,current=++cntx;
        t[current].siz=1;t[current].num=x;
        while(1) {
            t[now].siz++;
            bool child=x>=t[now].num;
            if(t[now].son[child])
                now=t[now].son[child];
            else {
                t[t[now].son[child]=current].fa=now;
                break;
            }
        }
        int need=0;
        for(int i=current;i;i=t[i].fa)
            if(!balance(i))
                need=i;
        if(need)
            rebuild(need);
    }
    inline int get_kth(int x) {
        int now=root;
        while(1) {
            if(t[t[now].son[0]].siz==x-1)
                return now;
            else if(t[t[now].son[0]].siz>=x)
                now=t[now].son[0];
            else {
                x-=t[t[now].son[0]].siz+1;
                now=t[now].son[1];
            }
        }
        return now;
    }
    inline void init() {
        cntx=2;root=1;
        t[1].num=-oo,t[1].siz=2,t[1].son[1]=2;
        t[2].num=oo,t[2].siz=1,t[2].fa=1;
    }
    int n,q,val[300001],pos,o[300001];
    inline void main() {
        init();
        read(n);read(q);
        for(int i=1;i<=n;i++)
            read(val[i]);
        for(int i=1;i<=q;i++)
            read(o[i]);
        int pos=1;
        for(int i=1;i<=n;i++) {
            insert(val[i]);
            while(o[pos]==i)
                writeln(t[get_kth(pos+1)].num),pos++;
        }
    }
}SGT;
int main() {
    SGT.main();
    return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值