STL

容器

通用操作

O(1) size() ,empty()

O(N) clear()

vector向量——变长数组

头文件:

#include<vector> 

创建:

vectora; vector<类型名>变量名

操作:

O(1)

a.empty(); bool

!!! 下标访问 0~ a.size()

a.push_back();

a.pop_back();

a.begin();//头指针,数组非空 *a.begin()=a[0]

a.end(); //尾指针,取尾元素的下一个地址。就相当于左闭右开区间。

两种遍历(只有vector 和 string 可以下标遍历)

vector<int>v;
int main(){
    for(int i=5;i;i--)
        v.push_back(i*2);
    for(vector<int>::iterator it=v.begin();it!=v.end();it++) 
        printf("%d
",*it);
    for(int i=0,siz=v.size();i<siz;i++)
        printf("%d
",v[i]);
    return 0;
}

O(n)

a.insert()

a.eraser()

比较:

sort(vec.begin(), vec.end(), cmp);

应用

vector 存图

伪平衡树:

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <vector>
using namespace std;
inline int read(){
    int x=0,f=1;char ch=getchar();
    while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
    while(isdigit(ch)){x=x*10+ch-'0';ch=getchar();}
    return x*f;
}
vector <int> v;
int n;
int main(){
    n=read();
    for(int i=1,opt,x;i<=n;i++){
        opt=read();x=read();
        if(opt==1) v.insert(lower_bound(v.begin(),v.end(),x),x);
        if(opt==2)  v.erase(lower_bound(v.begin(),v.end(),x));
        if(opt==3)  printf("%d
",lower_bound(v.begin(),v.end(),x)-v.begin()+1);
        if(opt==4)  printf("%d
",v[x-1]);
        if(opt==5)  printf("%d
",*--lower_bound(v.begin(),v.end(),x));
        if(opt==6)  printf("%d
",*upper_bound(v.begin(),v.end(),x));
    }
    return 0;
}

string

头文件:

#include <string>

创建:

string s

操作:

求串的长度:s.size() //不能用strlen

求一个子串:s.substr(开始的位置, 长度) //位置从0开始编号,返回一个string

连接字符串:s = a + b

s1==s2判断是否相等

s1=s2将 s1 赋值为 s2

查找一个字母第一次出现位置:s.find(ch) //返回一个int,从0开始编号

输入输出请使用cin/cout,不能用scanf/printf

cctype中

isalnum(c) 如果c是字母或数字,则为true
isalpha(c) 如果c是字母,则为true
isdigit(c) 如果c是数字,则为true
islower(c) 如果c是小写字母,则为ture
isupper(c) 如果c是大写字母,则为true
isspace(c) 如果c是空白字符,则为true
ispunct(c) 如果c是标点符号,则为true
iscntrl(c) 如果c是控制字符,则为true
isgraph(c) 如果c不是空格,但是可打印,则为true
isprint(c) 如果c是可打印的字符,则为true
isxdigit(c) 如果c是十六进制数,则为true
tolower(c) 如果c是大写字母,则返回其小写字母形式,否则直接返回c
toupper(c) 如果c是小写字母,则返回其大写字母形式,否则直接返回c

s.substr(pos,n) 返回一个string类型的字符串,它包含s中从下标pos开始的n个字符
s.substr(pos) 返回一个string类型的字符串,它包含从下标pos开始到s末为的所有字符

s.find(args) 在s中查找args的第一次出现
s.rfind(args) 在s中查找args的最后一次出现
s.find_first_of(args) 在s中查args的任意字符的第一次出现
s.find_last_of(args) 在s中查找args的任意字符的最后一次出现
s.find_first_not_of(args) 在s中查找第一个不属于args的字符
s.find_last_not_of(args) 在s中查找最后一个不属于args的字符

两种遍历

   for(it=s.begin();it!=s.end();++it)
        cout<<*it<<endl;
    for(int i=0;s[i];i++)
        cout<<s[i]<<endl;

bitset

状态压缩神器,复杂度: O(n / 32)

#include <bitset>
...
bitset<N> state1, state2;
//初始化:全为0
//state1 : 第0位 ~ 第N - 1位
...
state1 = ~state1;
state1 &= state2;
state1 |= state2;
state1 ^= state2;
state1 <<= 1;
state1 >>= 1;
if (state1 == state2)   ...
if (state1 != state2)   ...
int d3 = state1[3];
state1[0] = 1;
int tot = state1.count();

deque双端队列

头文件:

#include<deque>

创建:

deque q;

操作:

a.push_back();

a.push_front();

a.pop_back();

a.pop_front();

应用:

双端bfs ——0 放前面 1放后面

void work(){
    deque <node> q;
    memset(dis,0x3f,sizeof(dis));
    dis[in[s]]=0;q.push_front({in[s],0});
    while(!q.empty()){
        int x=q.front().id;q.pop_front();
        if(vis[x])continue;
        vis[x]=1;
        for(int i=hd[x];i;i=e[i].nxt){
            int y=e[i].to,z=e[i].w;
            if(dis[y]>dis[x]+z){
                dis[y]=dis[x]+z;
                if(!vis[y]){
                    if(!z) q.push_front({y,dis[y]});
                    else q.push_back({y,dis[y]});
                }
            }
        }
    }
}

list双向链表

按顺序走到需存取的元素,O(n),在任何位置上执行插入或删除动作O(1)

头文件:

#include<list>

创建:

操作:

a.push_back();

a.push_front();

a.pop_back();

a.pop_front();

a.begin();//头指针

a.end(); //尾指针

a.erase(it) //将it位置删除

a.insert(it,elem);

a.insert(l1.begin(),l2.begin(),l2.end());在l1开始位置插入l2的从开始到结束的所有位置的元素

a.empty();

a.front() a.back()

a.merge():合并两个链表并使之默认升序

而 list 的迭代器是双向迭代器,所以以下代码可以:
	list<int> v;
	list<int>::const_iterator ii;
	for( ii = v.begin(); ii != v.end ();ii ++ )
		cout << * ii;	
以下代码则不行:
	for( ii = v.begin(); ii < v.end ();ii ++ )
		cout << * ii;	
	//双向迭代器不支持 <
	for(int i = 0;i < v.size() ; i ++)
		cout << v[i]; //双向迭代器不支持 []

pair

pair的实现是一种结构体,主要的两个成员变量是first, second

头文件:

#include<utility>

创建:

$ pair<T1, T2> p; $

//创建一个空的pair对象,它的两个元素分别是T1和T2类型 ——可以是int ,double ,char ,string.....

应用:

图论里有边权

$ vector< pair<int,int> > g[N] $

g[x].push_back(make_pair(y,z))

$ y=g[x][i].first ,w=g[x][i].second $

或者代替二元结构体

诡异离散化

#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;
const int N=4e6+10;
inline int read() {
	int x=0,f=1;char ch=getchar();
	while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
	while(isdigit(ch)){x=x*10+ch-'0';ch=getchar();}
	return x*f;
}
int n,m,cnt;
int b[N],c[N];
pair<int,int>a[N];
void update(int x){
    for(;x<=N;x+=x&(-x))
        c[x]++;
}
int query(int x){
    int res=0;
    for(;x;x-=x&(-x))
        res+=c[x];
    return res;
}
int ans;
bool cmp(pair<int,int> a,pair<int,int> b){
    return a.second<b.second;
}
int main(){
    n=read();
    for(int i=1;i<=n;i++) a[i]=make_pair(read(),i);
    sort(a+1,a+1+n);
    for(int i=1;i<=n;i++) a[i].first=i;
    sort(a+1,a+1+n,cmp);
    for(int i=1;i<=n;i++){
        update(a[i].first);
        ans=max(ans,i-query(a[i].first));
    }
    printf("%d
",ans+1);
    return 0;
}

比较:

p1 < p2; 先比first,再比second

p1 == p2; first和second依次相等

排序

sort(a,a+n);   //默认对Item的first的值进行排序

自定义的sort()函数

bool cmp(pair<int, int>a, pair<int, int>b){
    return a.first<b.first;            //根据fisrt的值升序排序
}    
bool cmp(pair<int, int>a, pair<int, int>b){
    return a.first>b.first;            //根据second的值升序排序
}

Map/Multimap映射

Map的元素是成对的键值/实值,内部的元素依据其值自动排序,Map内的相同数值的元素只能出现一次,Multimaps内可包含多个数值相同的元素,内部由二叉树实现,便于查找;O(logn)

头文件:

#include<map>

创建:

map<类型1,类型2>变量名

操作:

map的两种访问方式:下标访问、迭代器访问

mp[“abc”]=2;

mp.find()返回值是一个迭代器,成功返回迭代器指向要查找的元素,失败返回的迭代器指向end。*

mp.count()方法返回值是一个整数,1表示有这个元素,0表示没有这个元素————BSGS里用到

应用:

字符串对应

CF650A Watchmen

注意去重

queue队列

priority_queue优先队列,大根堆

堆的应用戳这里

先进先出

头文件:

#include<queue>

操作:

a.push();//优先队列是O(logN)

a.empty();

a.front(); //优先队列是 a.top() O(1)

a.back();

a.pop(); //优先队列O(logN)

应用:

priority_queue<int,vector<int>,greater<int>> pq;
//优先队列总是把最小的元素放在队首。

priority_queueK<int,vector<int>,less<int>> pq;
//优先队列总是把最大的元素放在队首。

stack栈

后进先出

头文件:

#include<stack>

创建:

stack s;

操作:

a.push();

a.top();

a.pop();

应用:

用来模拟实现递归。程序的栈内存空间很小,如果用普通递归,可能会导致程序运行崩溃。

用栈模拟递归可以避免这种问题。

set集合

set内的元素,自动递增排序,并且去重。

头文件:

#include<set>

创建:

操作:

    for(set<int>::iterator it=st.begin();it!=st.end();it++)  {
        printf("%d ",*it);
    }

O(logN):

insert()

find()

erase()

erase(a,b);删除左闭右开区间内[a,b)的元素,时间复杂度为O(b-a)

应用:

查询前驱后继:

  set<int>::iterator l=--s.lower_bound(x);      set<int>::iterator r=s.lower_bound(x);
cout<<*l<<“ ”<<*r<<endl;

查找一个元素是否在set里:

it = s.find(x);

如果有x,返回其迭代器,否则返回s.end();

set<int>s;
int main(){
    s.insert(N);s.insert(-N);
    for(int i=5;i;i--)
        s.insert(i*2);
    set<int>::iterator it;
    for(int i=1;i<=10;i++)  {
        it=s.find(i);
        if(it==s.end()) puts("NO");
        else printf("%d
 ",*it);
    }
    return 0;
}

邻值查找

注意开long long

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<set>
#include <limits.h>
using namespace std;
typedef long long ll;
set<pair<int,int>> s;
int main(){
    int n;
    cin>>n;
    s.insert({-0x7fffffff,0}); 
    s.insert({0x7fffffff,0});
    for(int i=1;i<=n;i++){
        int v;
        cin>>v;
        if(i>1){
            auto it=s.upper_bound({v,0});//任意位置,所以可以为0(只是用v的值来查找)
            auto jt=it;
            jt--;
            ll ans1=(ll)v-jt->first,ans2=it->first-(ll)v;
            if(ans1<=ans2) cout<<ans1<<" "<<jt->second<<endl;
            else cout<<ans2<<" "<<it->second<<endl;
        }
        s.insert({v,i});
    }

} 


原文地址:https://www.cnblogs.com/ke-xin/p/13544616.html