(STL)大法好
set
闲话不多说,在神奇的(STL)库里面,有一个非常非常好用而且强的(STL)叫(set),内部实现是一棵平衡树。它神奇的地方就在于可以对插入、删除、查找在(O(logn))的时间复杂度内实现,并且相当于维护了一个有序序列。(set)内部没有重复的元素,而(multiset)内部可以有重复的元素。下面介绍几个常用操作。
定义
#include<set>
...
set<int> s;
插入
s.insert(x)表示将值为x的元素插入set中,set会维护有序序列
删除
s.erase(x)表示删除值为x的元素
s.erase(it)表示删除指针为it的元素
s.erase(x);
与
set<int>::iterator it=s.find(x);
if(it!=s.end()) s.erase(it);
等效(multiset中不是
要注意的是,第一个删除会所有值为(x)的元素,而第二个删除只会删除一个。对于(set)而言,这两种操作没有任何区别。但对于(multiset),就要看情况选择删除全部还是删除(1)个。
查找
s.find(x)表示查询值为x的位置,会返回x的指针。如果不存在该元素会返回x.end()
set<int>::iterator it=s.begin();
*it即为最大元素
set<int>::iterator it=--s.end();
*it即为最小元素
二分
s.lower_bound(x)即为查找大于等于x的第一个数的指针
s.upper_bound(x)即为查找大于x的第一个数的指针
可以用于查找前驱后继
遍历
set<int> s;
for(int i=1;i<=n;i++) s.insert(a[i]);
for(set<int>::iterator it=s.begin();it!=s.end();it++) cout<<*it<<endl;
学长出的例题
思路
首先前六个操作都是白给。插入删除,前驱后继,最大最小,用上述函数即可。而对于操作七,考虑维护一个全局加变量。每次插入时将插入的(x)减去全局加变量加到(multiset)中,然后每次取出的时候再加上全局加变量输出就可以了。而且要注意二分求前驱后继的时候也要查询(x-add)。
代码
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<set>
#define ll long long
using namespace std;
int q;
ll las,add,op,x;
multiset<ll> s;
int main()
{
scanf("%d",&q);
for(int i=1;i<=q;i++){
scanf("%lld",&op);
op=op ^ las;
if(op==1){
scanf("%lld",&x);
x-=add;
s.insert(x);
}
if(op==2){
scanf("%lld",&x);
multiset<ll>::iterator it=s.find(x-add);
if(it!=s.end()){
s.erase(it);
}
}
if(op==3){
if(!s.size()){
printf("zay
");
}
else{
multiset<ll>::iterator it=--s.end();
las=*it+add;
printf("%lld
",las);
}
}
if(op==4){
if(!s.size()){
printf("zay
");
}
else{
multiset<ll>::iterator it=s.begin();
las=*it+add;
printf("%lld
",las);
}
}
if(op==5){
scanf("%lld",&x);
multiset<ll>::iterator it=s.lower_bound(x-add);
if(it==s.begin()){
printf("cuc
");
}
else{
it--;
las=*it+add;
printf("%lld
",las);
}
}
if(op==6){
scanf("%lld",&x);
multiset<ll>::iterator it=s.upper_bound(x-add);
if(it==s.end()){
printf("cyc
");
}
else{
las=*it+add;
printf("%lld
",las);
}
}
if(op==7){
scanf("%lld",&x);
add+=x;
}
}
return 0;
}