码迷,mamicode.com
首页 > 其他好文 > 详细

黑匣子

时间:2017-08-18 21:24:39      阅读:160      评论:0      收藏:0      [点我收藏+]

标签:scan   编号   等于   []   排序   printf   while   padding   命令   

                                              

                                      黑匣子

Description:

       我们使用黑匣子的一个简单模型。它能存入一个整数序列和一个特别的变量i。在初始时刻,黑匣子为空且i等于0。这个黑匣子有执行一系列的命令。有两类命令:

      ADD(X):把元素X放入黑匣子;

      GET:把i加1的同时,输出黑匣子内所有整数中第i小的数。牢记第i小的数是当黑匣子中的元素已非降序排序后位于第i位的元素。

下面表是一个11个命令的例子:

编号

命令

I

黑匣子内容

输出

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

 

       现需要一个有效的算法处理给定的一系列命令。ADD和GET命令总数至多有30000个。定义ADD命令的个数为M个,GET命令的个数为N个。我们用下面两个整数序列描述命令序列:

       (1)A(1),A(2),…,A(M):加入黑匣子的元素序列。所有的数均为绝对值不超过2000000的整数。例如在上例中A=(3,1,-4,2,8,-1000,2)。

       (2)u(1),u(2)…,u(N):u(i)表示第i个GET命令在第u(i)个ADD命令之后,例如在上例中,u=(1,2,6,6,)。

  你可以假定自然数序列u(1),u(2),…,u(N)以非降序排列,N<=M,且对于每一个p(1<=p<=N)有p<=u(p)<=M。

 

Input

       第一行存放M和N的值,第二行存放 A(1),A(2),……,A(M) ,第三行存放u(1),u(2),……,u(N)。

Output

      输出黑匣子的处理结果。

Sample Input

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

Sample Output

3
3
1
2

Data Size

1<=n<=m<=30000

题解

       此题的询问次数和要查询的数值是数列中第几大有关,就可以考虑用对维护。
       需要两个堆,一个维护前 j(询问数)-1小的数中的最大值(大根堆),一个维护剩下的数中的最小值(小根堆)。
       按顺序遍历这个数列,对于当前这个数,如果这个数比第二个堆的堆顶要小,把这个数插入到第一个堆,再把第一个堆的堆顶取出来,放到第二个堆,确保第一个堆只有j-1个数。否则就插入到第二个堆。

       对于当前位置的询问,ans为第二个堆的堆顶,然后把第二个堆的堆顶放到第一个堆里去,询问数多了一次,所以前j-1个数的堆也要多一个数。(手打堆)

 1 #include<iostream>
 2 #include<cstdio>
 3 using namespace std;
 4 int n,m,q,cnt_s=0,cnt_b=0;
 5 int d_s[300006],d_b[300006];//d_s[]为小根堆  d_b[]为大根堆 
 6 int a[300006],b[300006];
 7 void push_s(int x){
 8     d_s[++cnt_s]=x;
 9     int now=cnt_s;
10     int fa=now/2,t;
11     while(fa>0&&d_s[now]<d_s[fa]){
12         t=d_s[fa];d_s[fa]=d_s[now];d_s[now]=t;
13         now=fa;fa=now/2;
14     }
15 }
16 void push_b(int x){
17     d_b[++cnt_b]=x;
18     int now=cnt_b;
19     int fa=now/2,t;
20     while(fa>0&&d_b[now]>d_b[fa]){
21         t=d_b[fa];d_b[fa]=d_b[now];d_b[now]=t;
22         now=fa;fa=now/2;
23     }
24 }
25 void pop_s(){
26     d_s[1]=d_s[cnt_s];cnt_s--;
27     int now,lc,rc,t;
28   now=1;lc=2;rc=3;
29     while((d_s[now]>d_s[lc]||d_s[now]>d_s[rc])&&lc<=cnt_s){
30         if(d_s[now]>d_s[lc]||rc>cnt_s){
31             t=d_s[now];d_s[now]=d_s[lc];d_s[lc]=t;
32             now=lc;lc=now*2;rc=lc+1;
33         }
34         else{
35             t=d_s[now];d_s[now]=d_s[rc];d_s[rc]=t;
36             now=rc;lc=now*2;rc=lc+1;
37         }
38     }
39 }
40 void pop_b(){
41     d_b[1]=d_b[cnt_b];cnt_b--;
42     int now,lc,rc,t;
43   now=1;lc=2;rc=3;
44     while((d_b[now]<d_b[lc]||d_b[now]<d_b[rc])&&lc<=cnt_b){
45         if(d_b[now]<d_b[lc]||rc>cnt_b){
46             t=d_b[now];d_b[now]=d_b[lc];d_b[lc]=t;
47             now=lc;lc=now*2;rc=lc+1;
48         }
49         else{
50             t=d_b[now];d_b[now]=d_b[rc];d_b[rc]=t;
51             now=rc;lc=now*2;rc=lc+1;
52         }
53     }
54 }
55 int main(){
56     scanf("%d%d",&n,&m);
57     for(int i=1;i<=n;i++)scanf("%d",&a[i]);
58     for(int i=1;i<=m;i++)scanf("%d",&b[i]);
59     int j=1;
60     for(int i=1;i<=n;i++){
61         if(a[i]<d_s[1]){
62             push_b(a[i]);
63             q=d_b[1];
64             push_s(q);pop_b();
65         }else
66         {
67             push_s(a[i]);
68         }
69         while(b[j]==i){
70             q=d_s[1];printf("%d\n",q);
71             push_b(q);
72             pop_s();j++;
73         }
74     }
75 }

 

黑匣子

标签:scan   编号   等于   []   排序   printf   while   padding   命令   

原文地址:http://www.cnblogs.com/ttaro/p/7390273.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!