您的位置:首页 > 理论基础 > 数据结构算法

堆/平衡树——Luogu1801 黑匣子_NOI导刊2010提高(06)

2017-04-07 08:30 197 查看
https://www.luogu.org/problem/show?pid=1801

那个,这个标题一开始我以为是飞机上的黑匣子。。。



进入正题,输出第k小

我们来脑洞大开一下,因为k是递增的,所以过程相当于不可逆

那么我们可以考虑开两个二叉堆,一个小根堆,一个大根堆

我们限制大根堆的大小为k-1(即要求的第k小-1)

每次插入先入大根堆,如果大根堆大小超过k-1,把大根堆顶的数扔到小根堆里去

询问时输出小根堆顶即可,然后大根堆大小+1,把这个数扔过去就好了

正确性显然

#include<bits/stdc++.h>
using namespace std;
priority_queue<int>q1;
priority_queue<int,vector<int>,greater<int> >q2;
int a[200001],k,r,cnt=0;
inline void insert(int x){
q1.push(x);
while(q1.size()>cnt){
q2.push(q1.top());
q1.pop();
}
}
inline int find(){
cnt++;int ans=q2.top();
q1.push(ans);
q2.pop();return ans;
}
int main()
{
k=0,r=0;
int n,m;scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)scanf("%d",&a[i]);
for(int i=1;i<=m;i++){
int x;scanf("%d",&x);
for(;r<x;r++)insert(a[r+1]);
printf("%d\n",find());k++;
}
return 0;
}


其实啊,非区间k值这种问题交给平衡树最好了。。。

只有插入和询问的splay奉上(虽然没前面那个快。。。)

#include<bits/stdc++.h>
using namespace std;
int a[200001];
int t[1000001][2],fa[1000001],s[1000001],val[1000001],v[1000001];
int n,m,tt,rt,del,pr,su;
inline void pushup(int x){s[x]=s[t[x][0]]+s[t[x][1]]+v[x];}
inline void turn(int x,int &p){
int y=fa[x],z=fa[y],l,r;
if(t[y][0]==x)l=0;else l=1;
r=l^1;
if(y==p)p=x;
else if(t[z][0]==y)t[z][0]=x;
else t[z][1]=x;
fa[x]=z;fa[y]=x;fa[t[x][r]]=y;
t[y][l]=t[x][r];t[x][r]=y;
pushup(y);pushup(x);
}
inline void splay(int x,int &p){
int y,z;while(x!=p){
y=fa[x];z=fa[y];
if(y!=p){
if((t[y][0]==x)^(t[z][0]==y))turn(x,p);
else turn(y,p);
}
turn(x,p);
}
}
inline void insert(int k){
if(!rt){
tt++;rt=tt;
val[tt]=k;s[tt]=v[tt]=1;
return;
}
int p=rt,z;
while(p){
z=p;s[p]++;
if(k<val[p])p=t[p][0];
else if(k>val[p])p=t[p][1];
else{v[p]++;pushup(p);splay(p,rt);return;}
}
if(val[z]>k)t[z][0]=++tt;
else t[z][1]=++tt;
val[tt]=k;s[tt]=v[tt]=1;fa[tt]=z;
splay(tt,rt);
}
inline int find(int x,int k){
if(k<=s[t[x][0]])return find(t[x][0],k);
if(k>s[t[x][0]]&&k<=s[t[x][0]]+v[x])return val[x];
return find(t[x][1],k-s[t[x][0]]-v[x]);
}
int main()
{
int k=0,r=0;
int n,m;scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)scanf("%d",&a[i]);
for(int i=1;i<=m;i++){
int x;scanf("%d",&x);
for(;r<x;r++)insert(a[r+1]);
k++;printf("%d\n",find(rt,k));
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  数据结构