这道题可以用Splay、fhq-treap解决,但是平衡树解这道题大材小用,所以我采用了对顶堆解决。
考虑建立两个堆:以i为分割点,用大根堆存储前半段序列,用小根堆存储后半段序列。我们控制大根堆的元素个数为i,这样查询时大根堆的堆顶就是排名为i的元素。然后我们考虑维护对顶堆。
对于add操作,我们先将元素放入下面的大根堆内,从堆顶不断取出元素放到小根堆直到大根堆元素个数为i,这样大根堆的根就是第i小的元素,同时可以保证对顶堆的性质;
同理,对于get操作,我们先输出大根堆的根,然后将小根堆的根移到大根堆(因为i每次加一,要始终保证大根堆有i个元素),这样仍保证对顶堆的性质不变
因此,时间复杂度为O(nlog2n),我们用STL的优先队列即可完成。
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <algorithm> 5 #include <queue> 6 using namespace std; 7 typedef long long ll; 8 int n,m,a[200010]; 9 priority_queue<int> maxx; 10 priority_queue<int,vector<int>,greater<int> >minn; 11 int main() { 12 scanf("%d%d",&n,&m); 13 for(int i=1;i<=n;i++) 14 scanf("%d",&a[i]); 15 int now=1; 16 for(int i=1;i<=m;i++) { 17 int x; 18 scanf("%d",&x); 19 for(int j=now;j<=x;j++) { 20 maxx.push(a[j]); 21 if(maxx.size()==i) minn.push(maxx.top()),maxx.pop(); 22 } 23 now=x+1; 24 printf("%d\n",minn.top()); 25 maxx.push(minn.top()); 26 minn.pop(); 27 } 28 return 0; 29 }