STL中的使用技巧
不定期更新
\(①\) 对于 \(x\) , \(y\) , 我们想知道两者是否匹配.
\(sol_1\) \(:\) 用二维数组 , 但显然 \(x\) , \(y\) 范围一大则不行.
\(sol_2\) \(:\) 可以选择以 \(x\) 为点 , 建造关于 \(x\) 的有向图 , 把边跑一下看是否有 \(y\).
\(sol_3\) \(:\) 用 \(map\) , 直接上代码.
map<pair<int,int>,bool> ext;
if(ext[make_pair(x,y)]) continue;
ext[make_pair(x,y)] = 1;
\(fill\) 的使用.
既可以对整形又可以对字符型数组赋值 , 例如 \(:\) $fill(a+1,a+1+n,2) $ , 将数组 \(a\) 的 \([1,n]\) 赋值为 \(2\) .
对于二维数组 \(fill(a[i],a[i]+n+1,2)\) 完成对某一行的赋值.
大小根堆
\(①\) \(:\) 大根堆 \(priority_queue<int> Q\) 或者 $priority_queue<pair<int,int> > Q $
这一点在最短路的 \(Dijkstra\) 中提到
\(②\) \(:\) 小根堆
方法一 \(:\) 将 大根堆 中的元素均取反 , 小的变成大的 , 这在 \(Dijkstra\) 中提到.
方法二 \(:\) 自带的 \(stl\) , \(priority_queue<int,vector<int>,greater<int> > Q\)
方法三 \(:\) 重载优先队列中的小于号.
struct rec{int id;double value; };
priority_queue<rec> Q;
friend bool operator <(rec a,rec b){ //要声明为友元函数
return b.value < a.value; // 在优先队列中使用时 , b 作为头节点 , 这里就表示小根堆
}
等价于
bool operator<(cosnt Node &t) const{
reutrn t.value < value; //优先队列中使用时 , t 作为头节点
}
但注意如果时配合 sort 使用的话 ,上述大小方向要调换
vector<rec> q;
sort(q.begin(),q.end());
friend bool operator <(rec a,rec b){ //要声明为友元函数
return a.value < b.value; // a作为序号小的
}
bool operator<(cosnt Node &t) const{
reutrn value < t.value; //优先队列中使用时 , t 作为头节点
}
这启示我们 , 结构体代替 \(pair\) , 队列可以带多个元素.
重载 \(<\) 可以满足多个且复杂的要求.
typedef pair<int,int> PII;
PII a[N] ; sort(a+1,a+1+n) ;
排序会按照第一关键字 , 第二关键字从小到大排序.
unique
注意 \(unique\) 是去除相邻且重复的元素
\(① :\) 针对于数组使用
#include<algorithm> // 头文件
直接使用 unique(a+1 , a+1+n) ; // 1 2 2 3 3 4 4 -> 1 2 3 4 3 3 4.
结合使用 : len = unique(a+1 , a+1+n) - (a+1) ; //找出去重之后的长度 , 如上个样例的len 就为 4.
vector
unique(a.begin() , a.end()) ; //注意这个 unique 会返回迭代器 , 指向去重之后末尾元素的下一个位置.
配合 : a.erase( unique(a.begin() , a.end()) , a.end()) ; // 注意 a.end()在unique之后不变.
reverse
在数组反转中应用广泛.
#include<algorithm> // reverse头文件
#include<cstring>
char c[1001] ; scanf("%s",c+1);
int len = strlen(c+1);
reverse(c+1,c+1+len);
vector<int> Q ; reverse(Q.begin(),Q.end());
vector
\(① :\) \(vector\) 配合 \(find , lowber\_bound , upper_bound\) 函数
vector<int> Q;
find(Q.begin() , Q.end() , target) - Q.begin();
lowber_bound(Q.begin() , Q.end() , target) - Q.begin() ;
upper_bound(Q.begin() , Q.end() , target) - Q.begin();
count(Q.begin() , Q.end() , target) // target 在 Q 中的数量
Q.assign(n , target) ; // 将 Q 之前的存储全部清空 , 存入 n 个 target
set
\(① :\) \(set\) 可配合 \(pair\) 使用 \(lower\_bound\) , \(find\) 函数
pair<pair<int,int> > Q //注意最后的两个箭头要隔开.
pair<int,int> w ; w.first = x , w.second = y;
Q.lower_bound(w) ; //调用set自我的lower_bound 比 调用 algorithm 中的 lower_bound 快.
//cf div2 875
set p;
for(auto f : p) {
p.erase(*f); //这样是错的 , 靠 prev,next 移动 , 删除该节点后移动会出现错误.
}
p.rbegin() ; //区别于p.end() , 就是最后一个元素
auto it = p.insert(x) ; // insert是会返回对应位置的迭代器的
auto if = p.erase(x) ; // 返回删除下一个位置的迭代器,如果本身是末尾 , 那么返回 end()
std::set<int> g[n] ;
std::vector<std::set<int>> g(n); //等价前者
g[i].insert(x); //插入
sort
sort 从大到小排序
sort(a + 1 , a + 1 + n , greater<int>());
sort(a.begin() , a.end() , greater<int>());
string
string s;
s.find(c) == string::npos ; //找不到
count(s.begin(),s.end(),c); 字符 c 在字符串 s 中的个数
alorithm类函数
lower_bound(a.begin() , a.end() , target) - a.begin() ; //target不存在时返回 a.end()
无论是 vector 还是数组 , 当 target 不存在时 , 都是返回末尾第一个没有元素的位置.
deque
deque<int> q;
q.push_back() , q.push_front();
q.pop_back() , q.pop_front();
//队列,但有push_back() , 同 vector
map
map<int,int> p;
p.lower_bound(x) ; // lower_bound , upper_bound 针对于 key 值进行查找
auto l = p.lower_bound(x) , r = p.lower_bound(y);
p.erase(l);
p.erase(l , r); 删除 [l , r) 范围
multiset
multiset<int> p;
[1 , 2 , 2 , 2 , 3 , 4]
p.erase(2); // 1,3,4
auto f = p.find(2);
p.erase(f) ; // 1,2,2,3,4
std::multiset 中 extract
从multiset中提取并删除一个特定元素
p.extract(2); // 1 , 2 , 2 , 3 , 4
assert
便于调试 bug
array
array<int,4> ans;
ans = std::max(ans , ...);
//会按字典序依次比较大小
mt19937
随机化
std::mt19937 mrand(std::random_device{}());
int x = mrand() % mod;
clock()
例子:卡时1.9s (cpu运行时间)
while (std::clock() <= 1.9 * CLOCKS_PER_SEC) {
}
std::__lg(x)
std::__lg(x) ; //底数为 2
accumulate
ll x = std::accumulate(a.begin() , a.end() , 0ll);

浙公网安备 33010602011771号