TYVJ 1434 黑匣子
发布日期:2022-02-05 18:27:28 浏览次数:16 分类:技术文章

本文共 3478 字,大约阅读时间需要 11 分钟。

描述 Description

Blackbox是一种原始的数据库。它可以储存一个整数数组,还有一个特别的变量i,最开始的时候blackbox是空的,而i等于0。这个blackbox要处理一串命令。
命令只有两种:
Add(x):把x元素放进blackbox;
Get:i加1,然后输出blackbox中第i小的数。
记住:第i小的数,就是blackbox里的数的按从小到大的顺序排序后的第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命令分别最多有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=(1,2,6,6)。输入数据不用判错。

输入格式 InputFormat

第1行:两个整数M,N。
第2行:M个整数,表示A(1)……A(m)
第3行:N个整数,表示u(1)……u (n)

输出格式 OutputFormat

输出black box根据命令串所得出的输出串,一个数字一行。

样例输入 SampleInput 

7 43 1 -4 2 8 -1000 21 2 6 6 

样例输出 SampleOutput 

3312

来源 Source

By:space7

话说一看到区间k大就想到了平衡树 可惜本蒟蒻不会treap等等树 害的我都想去学了。。。

然后就写模拟了

名其曰”滑动数组“ 。。。

二分插入位置 后面的都向后挪1个位置 插入这个数

查询直接输出第k个就是第k小

然后可以过30

同学有写每次插入到末尾然后sort的 可以得40/50

还有写multiset的 好像可以40/50

大神直接上平衡树秒杀了蒟蒻们。。。

另一位大神两个堆秒杀了蒟蒻们。。。

本蒟蒻感觉两个堆还是有参考意义的

还可以用双堆求中位数

先说一下求中位数吧   一串数s1,s2.....sn  首先中位数mid是s1

一个小根堆  一个大根堆

从s2向后 若s>mid 放到小根堆中

否则放入大根堆

若两堆内元素相差大于2时 将m放入元素少的堆中 从元素多的堆中取一个 为新的中位数

若最后两堆元素相同 中位数为mid

否则为mid和 堆中元素多的那个堆的堆顶

然后再说一下这个题

看到双堆求中位数后 我想到了用mid维护第k小

一个大根堆ql 一个小根堆qr

首先mid=s1

从s2向后

若s比mid小 放入ql中 否则放入qr中

若ql中元素个数>k-1     mid入qr   mid=ql的堆顶 ql弹出堆顶

查询时  若ql中元素不足k-1个 mid入ql  mid=qr的堆顶 qr弹出堆顶

即严格让ql中数小于mid 个数=k-1 此时mid为第k小的数

不会手打heap 只能priority_queue...

还要注意优先队列的greater和less

#include
#include
#include
#include
using namespace std;priority_queue
,less
>ql;priority_queue
,greater
>qr;int l,r,mid;int m,n,a,b,c;int ask;int s[200022];int main(){ freopen("blackbox.in","r",stdin); freopen("blackbox.out","w",stdout); scanf("%d%d",&m,&n); for(a=1;a<=m;a++)scanf("%d",&s[a]); mid=s[1]; b=2; for(a=1;a<=n;a++) { scanf("%d",&ask); for(b;b<=ask;b++) { if(s[b]>mid) { qr.push(s[b]); } else { qr.push(mid); ql.push(s[b]); mid=ql.top(); ql.pop(); } } while(l

在看了题解后 发现区间k小居然可以线段树做。。。

当时又憨脸了

首先可以用线段树支持一下几个操作

1.给出x,使f[x]+1

2.求

i<=x-1                       i<=x

    Σ         f[i]<k   且     Σ     f[i]>=k          时的x

   i=1                          i=1

这个题就是这样

离散化后200000个点 用一个线段树支持上面的操作 然后就可以了。。。

太神奇了。。。

离散化是自己yy的 不知道对不对。。。

#include
#include
#include
#include
using namespace std;const int lim=200022;int sumv[lim<<2],m,n,a,b,c,ask;struct self{int x,y;}s[lim]; //s[x]=y;int transfor[lim],hash[lim],pm; //hash[离散后数值]=离散前下标 transfor[离散前下标]=离散后数值 int cmp(self a1,self a2){if(a1.y==a2.y)return a1.x
>1; if(i<=mid)add(o<<1,l,mid,i); else add(o<<1|1,mid+1,r,i); pushup(o);}int query(int o,int l,int r,int i){ if(l==r)return l; int mid=(l+r)>>1; int ret=0; if(i>sumv[o<<1]) ret=query(o<<1|1,mid+1,r,i-sumv[o<<1]); else ret=query(o<<1,l,mid,i); return ret;}int main(){ freopen("blackbox.in","r",stdin); freopen("blackbox.out","w",stdout); scanf("%d%d",&m,&n); for(a=1;a<=m;a++) { scanf("%d",&s[a].y); s[a].x=a; } sort(s+1,s+m+1,cmp); for(a=1;a<=m;a++) { if(s[a].y!=s[a-1].y)pm++; hash[pm]=a; transfor[s[a].x]=pm; } b=1; for(a=1;a<=n;a++) { scanf("%d",&ask); for(b;b<=ask;b++)add(1,1,pm,transfor[b]); cout<
<<'\n'; } return 0;}

转载地址:https://blog.csdn.net/li412302070/article/details/12977875 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!

上一篇:Software
下一篇:POJ 3063 Sherlock Holmes

发表评论

最新留言

留言是一种美德,欢迎回访!
[***.207.175.100]2024年04月11日 12时45分12秒