传送门:动态序列操作
在一个动态变化的序列中,完成以下基本操作:
(1)插入一个整数
(2)删除一个整数
(3)查找序列中最大的数
(4)查找序列中最小的数
(5)求x的前驱(前驱定义为不大于x的序列中最大的数)
(6)求x的后继(后继定义为不小于x的序列中最小的数)
输入
第一行为n,表示操作的次数,接下来有n行(n≤100000)
每行为以下操作之一:
(1)1 x:将x插入
(2)2 x:删除x,x在序列中一定存在,若有多个相同值,只删除一个。
(3)3:查找序列中最大的数
(4)4:查找序列中最小的数
(5)5 x:求x的前驱
(6)6 x:求x的后继
数据保证结果一定存在,其中序列中整数的绝对值不超过107。
输出
对于op取3、4、5、6等操作,输出相应的结果。
样例输入
10
1 2
3
1 5
4
1 10
2 5
1 3
6 8
1 11
5 3
样例输出
2
2
10
3
思路:
瞎搞:STL vector or 树状数组二分
正解:treap or splay(我也不会)
说说vector瞎搞吧,刚开始用set维护,需要另外有一个Map存是否删完了,于是光荣超内存了。扔了几天回头拿vector写了一发过了。
主要操作只有 insert:插入 earse:删除 , upper_bound ,lower_bound 两个对vector的二分查找。
lower_bound( begin,end,num):从数组的begin位置到end-1位置二分查找第一个大于或等于num的数字,找到返回该数字的地址
upper_bound( begin,end,num):从数组的begin位置到end-1位置二分查找第一个大于num的数字,找到返回该数字的地址
这里只需要注意,“不大于”,“不小于”这几个字眼即可。
代码:
#include<bits/stdc++.h> using namespace std; #define LL long long #define INF 2000000000 #define eps 1e-8 #define pi 3.141592653589793 vector<int>v; int main() { int _; for(scanf("%d",&_);_--;){ int cmd,x; scanf("%d",&cmd); if(cmd == 1){ scanf("%d",&x); v.insert(lower_bound(v.begin(),v.end(),x),x); }else if(cmd == 2){ scanf("%d",&x); v.erase(lower_bound(v.begin(),v.end(),x)); }else if(cmd == 3){ printf("%d\n",v[v.size()-1]); }else if(cmd == 4){ printf("%d\n",v[0]); }else if(cmd == 5){ scanf("%d",&x); vector<int>::iterator it = lower_bound(v.begin(),v.end(),x); if((*it) == x) printf("%d\n",x); else printf("%d\n",*(--it)); } else if(cmd == 6){ scanf("%d",&x); vector<int>::iterator it = upper_bound(v.begin(),v.end(),x); vector<int>::iterator itt = it; if(*(--itt) == x && itt!=v.begin()) printf("%d\n",x); else printf("%d\n",*it); } /*---test---*/ int f = 0; if(f == 1){ printf("zz :"); for(int i = 0 ; i < v.size() ; i ++) printf("%d ",v[i]); puts(""); } /*---test---*/ } return 0; }/* 10 1 2 3 1 5 4 1 10 2 5 1 3 6 8 1 11 5 3 144 1 1 2 1 1 1 1 3 2 3 1 3 1 10 2 10 1 10 1 10 1 11 6 10 6 10 5 10 6 9 6 -100 5 123123 */
600MS暴力做法
如果学完树状数组上二分,会更新一下树状数组二分的求解。