第K小數
Description
現在已有N個整數,你有以下三種操作:
1 A:表示加入一個值爲A的整數;
2 B:表示刪除其中值爲B的整數;
3 K:表示輸出這些整數中第K小的數;
Input
第一行,兩個整數N,M,表示最開始有N個整數,總共有M個操作
第二行用空格隔開的N個整數
接下來M行,每行表示一個操作
Output
若干行,一行一個整數,表示所求的第K小的數字
Sample Input
5 5
6 2 7 4 9
1 8
1 6
3 10
2 4
3 3
Sample Output
0
7
Hint
【注意】:如果有多個大小相同的數字,只把他們看做一個數字,如樣例。 若找不到第K小的數,輸出0
【數據範圍】
0<=N<=2,000,000
M<=1,000,000
-1,000,000,000<=每個整數<=1,000,000,000
法一:
裸的Splay:
代碼如下:
#include<iostream>
#include<cstdio>
using namespace std;
struct Tarjan{
int data;
int l;
int r;
int fa;
int cnt;
}Tree[3000005];
int Root=0;
int size=0;
void update(int x){
Tree[x].cnt=1;
if(Tree[x].l)Tree[x].cnt+=Tree[Tree[x].l].cnt;
if(Tree[x].r)Tree[x].cnt+=Tree[Tree[x].r].cnt;
}
void Rotate(int x){
int y=Tree[x].fa;
int z=Tree[y].fa;
if(Tree[y].l==x){
Tree[y].l=Tree[x].r;
if(Tree[x].r)Tree[Tree[x].r].fa=y;
if(z){
if(Tree[z].l==y)Tree[z].l=x;
if(Tree[z].r==y)Tree[z].r=x;
}
Tree[x].fa=z;
Tree[y].fa=x;
Tree[x].r=y;
}
if(Tree[y].r==x){
Tree[y].r=Tree[x].l;
if(Tree[x].l)Tree[Tree[x].l].fa=y;
if(z){
if(Tree[z].l==y)Tree[z].l=x;
if(Tree[z].r==y)Tree[z].r=x;
}
Tree[x].fa=z;
Tree[y].fa=x;
Tree[x].l=y;
}
update(y);
}
void Splay(int x){
int y;
int z;
while(Tree[x].fa){
y=Tree[x].fa;
z=Tree[y].fa;
if(!z){
Rotate(x);
break;
}
if((Tree[z].l==y)==(Tree[y].l==x)){
Rotate(y);Rotate(x);
}
else {
Rotate(x);Rotate(x);
}
}
update(x);
Root=x;
}
int find(int k){
int p=Root;
while(Tree[Tree[p].l].cnt+1!=k){
if(Tree[Tree[p].l].cnt+1>k){
p=Tree[p].l;
}
else {
k-=Tree[Tree[p].l].cnt+1;
p=Tree[p].r;
}
if(!p)return 0;
}
return p;
}
int Find(int k){
int p=Root;
while(p){
if(Tree[p].data==k)return p;
if(Tree[p].data>k)p=Tree[p].l;
else p=Tree[p].r;
}
return p;
}
void del(int k){
int p=Find(k);
if(!p)return;
Splay(p);
if(!Tree[p].l&&!Tree[p].r){
Root=0;
return;
}
if(!Tree[p].l){
Tree[Tree[p].r].fa=0;
Root=Tree[p].r;
return;
}
if(!Tree[p].r){
Tree[Tree[p].l].fa=0;
Root=Tree[p].l;
return;
}
int t=Tree[p].l;
Root=t;
Tree[t].fa=0;
while(Tree[t].r){
t=Tree[t].r;
}
Splay(t);
Tree[Tree[p].r].fa=t;
Tree[t].r=Tree[p].r;
update(t);
}
void insert(int data){
int t=Root;
int fa=0;
while(t){
fa=t;
if(Tree[t].data==data)return;
if(Tree[t].data>data)t=Tree[t].l;
else t=Tree[t].r;
}
int q=++size;
Tree[q].data=data;
Tree[q].l=0;
Tree[q].r=0;
Tree[q].fa=fa;
Tree[q].cnt=1;
if(Tree[fa].data>data)Tree[fa].l=q;
else Tree[fa].r=q;
Splay(q);
}
int n,m;
int main(){
scanf("%d%d",&n,&m);
int x,y;
for(int i=1;i<=n;i++){
scanf("%d",&x);
insert(x);
}
for(int i=1;i<=m;i++){
scanf("%d%d",&x,&y);
if(x==1){
insert(y);
}
if(x==2){
del(y);
}
if(x==3){
printf("%d\n",Tree[find(y)].data);
}
}
return 0;
}
法二:
由於沒有複雜的操作,
故可用stl;
提供兩份代碼:
tree(可能回編譯錯誤):
#include <cstdlib>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <algorithm>
#include <functional>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>
using namespace std;
using namespace __gnu_pbds;
tree<int,null_mapped_type,less<int>,rb_tree_tag,tree_order_statistics_node_update> t;
int main(){
int n,m,a,k;
scanf("%d%d",&n,&m);
for(int i=0,x;i<n;++i){
scanf("%d",&x);
t.insert(x);
}
while(m--){
scanf("%d%d",&a,&k);
if(a==1)t.insert(k);
else if(a==2)t.erase(k);
else printf("%d\n",t.size()<k?0:*t.find_by_order(k-1));
}
}
set:
#include<iostream>
#include<iomanip>
#include<cstring>
#include<cmath>
#include<cstdio>
#include<set>
using namespace std;
set<int> S;
set<int>::iterator it;
int main(){
int n,m;
scanf("%d%d",&n,&m);
int x,y;
for(int i=1;i<=n;i++){
scanf("%d",&x);
S.insert(x);
}
for(int i=1;i<=m;i++){
scanf("%d%d",&x,&y);
if(x==1){
S.insert(y);
}
if(x==2){
it=S.find(y);
if(it!=S.end()){
S.erase(it);
}
}
if(x==3){
for(it=S.begin();it!=S.end();it++){
y--;
if(y==0){printf("%d\n",*it);break;}
}
if(it==S.end())printf("0\n");
}
}
return 0;
}