P1801 Black Box _NOI Guide 2010 Improvement (06)

Topic description

Black Box is a primitive database. It can store an array of integers and a special variable i. Initially the Black Box is empty. and i is equal to 0. This Black Box has to process a sequence of commands.

There are only two commands:

ADD(x): put the x element into the BlackBox;

GET: add 1 to i, then output the i-th smallest number in Blackhox.

Remember: the i-th smallest number is the i-th element of the numbers in the Black Box sorted in ascending order. E.g:

Let's demonstrate a command string with 11 commands. (As shown below)

Now the requirement is to find out the best way to handle a given command string. ADD and GET commands each have a maximum of 200,000. Now use two integer arrays to represent the command string:

1.A(1), A(2),...A(M): A string of elements that will be put into the Black Box. Each number is an integer whose absolute value does not exceed 2000000000, M$200000. For example, the above example is A=(3, 1, a 4, 2, 8, -1000, 2).

2.u(1), u(2),...u(N): Indicates that a GET command appears after the u(j)th element is put into the Black Box. For example, u=(l, 2, 6, 6) in the above example. Enter data without making mistakes.

Input and output format

Input format:

The first line, two integers, M, N.

The second line, M integers, representing A(l)

……A(M)。

The third line, N integers, representing u(l)

…u(N)。

Output format:

Output the output string obtained by Black Box according to the command string, one number per line.

Input and output example

Input example #1: 
7 4
3 1 -4 2 8 -1000 2
1 2 6 6
Sample output #1: 
3
3
1
2

illustrate

For 30% of the data, M≤10000;

For 50% of the data, M≤100000:

For 100% of the data, M≤200000.

 

Solution:

  This question is a question to the top pile, but it is still a wave of weighted line segment trees of Amway. . .

  权值线段树其实很简单,故名思义它的每个叶子节点都有权值(即每个叶子节点维护的是某个确定的数),它可以很轻松的求出整个区间中的第$k$小的数(注意是整个区间,不是一段区间,权值线段树其实就是弱化的主席树,或者说主席树就是多棵权值线段树)。

  拿本题做例题。

  首先,我们对原数组离散化(因为数太大,空间开不下),这样离散后最多有$200000$个数,就能建树用叶子节点维护每个数了。

  再讲讲插入操作,其实就是单点修改,对于离散后的数每次找到它所在的叶子节点,使其权值$+1$(说明这个数出现了一次),并维护一段区间的数出现的个数(即区间求和)。

  然后询问第$k$小的数时,从整个区间$[1,n]$开始递归,当左儿子区间$[l,mid]$中出现的数个数大于等于$k$时,查询左儿子,否则查询右儿子中的第$k-sum[l,mid]$小的数(即左儿子中已有$sum[l,mid]<k$个数,那么整个区间第$k$小的数在右儿子里,且是右儿子中的第$k-sum[l,mid]$小的数),当查询到$l==r$时返回$l$就$ok$了。

代码:

 

 1 #include<bits/stdc++.h>
 2 #define il inline
 3 #define ll long long
 4 #define lson l,m,rt<<1
 5 #define rson m+1,r,rt<<1|1
 6 using namespace std;
 7 const int N=2e5+7;
 8 int tr[N<<2],n,m,u[N],s[N],cnt=1;
 9 struct numm{
10     ll v;int id;
11     bool operator < (numm a){return v<a.v;}
12 }a[N];
13 il ll gi(){
14     ll a=0;char x=getchar();bool f=0;
15     while((x>'9'||x<'0')&&x!='-')x=getchar();
16     if(x=='-')x=getchar(),f=1;
17     while(x>='0'&&x<='9')a=a*10+x-48,x=getchar();
18     return f?-a:a;
19 }
20 il void pushup(int rt){tr[rt]=tr[rt<<1]+tr[rt<<1|1];}
21 il void update(int u,int l,int r,int rt){
22     if(l==u&&r==u){tr[rt]++;return;}
23     tr[rt]++;
24     int m=l+r>>1;
25     if(u<=m)update(u,lson);
26     else update(u,rson);
27     pushup(rt);
28 }
29 il int query(int k,int l,int r,int rt){
30     if(l==r)return l;
31     int m=l+r>>1;
32     if(tr[rt<<1]>=k)return query(k,lson);
33     else return query(k-tr[rt<<1],rson);
34 }
35 int main()
36 {
37     n=gi(),m=gi();
38     for(int i=1;i<=n;i++)a[i].v=gi(),a[i].id=i;
39     for(int i=1;i<=m;i++)u[i]=gi();
40     sort(a+1,a+n+1);
41     for(int i=1;i<=n;i++)s[a[i].id]=i;
42     for(int i=1;i<=n;i++){
43         update(s[i],1,n,1);
44         while(i==u[cnt]){
45             printf("%lld\n",a[query(cnt,1,n,1)].v);
46             ++cnt;
47         }
48     }
49     return 0;
50 }

 

 

 

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=324929896&siteId=291194637