string
vector
queue、stack
(linked) list
deque
priority_queue
set、map
unordered_map?
每個容器都有empty()方法,表示容器是不是空的;如果試圖存取空容器的值可能會RE或取到亂數
只有序列容器有索引值,當然是左閉右開,小心別讓i<0或i>=size()
避免從空容器中讀取或pop東西
對於序列容器來說,他們的第一項和最後一項分別是front()和back()
queue是front(), stack是top()
類似指標,指向一個變數,可以用*it來存取那個變數
set、map沒有辦法直接用i=[0,size())遍歷,怎麼辦?
利用begin()、end()方法或for(type x:container)
find、lower_bound、upper_bound回傳的都是iterator
sort、fill等等也都需要傳入iterator
vector<int> vc;
for(vector<int>::iterator it = vc.begin(); it != vc.end(); ++it)
cin >> *it;
for(auto It = vc.begin(); It != vc.end(); ++It)
cout << *It << ' ';
cout << '\n';
int sum = 0;
for(int x:vc) sum += x;
cout << sum << '\n';
分類 | 說明 | 例子 |
---|---|---|
Input Iterator | 可讀的迭代器 支援*it (但不能修改) |
所有迭代器都是 |
Output Iterator | 可寫的迭代器 支援*it (可以修改) |
除了const_iterator以外都是 |
Forward iterator | 支援it++和++it | forward_list |
Bidirectional iterator | 支援++it, it++, --it, it-- | list、大部分的關聯容器 |
Random Access iterator |
支援it+k、it-k | 原生指標及序列容器 |
正向迭代器 [begin(), end())
反向迭代器 [rbegin(), rend())
不常用的const_iterator: cbegin(), cend(), crbegin(), crend()
vector<int> vi(100);
for(int &x:vi) cin >> x;
for(int x:vi) cout << x << '\n';
vector<map<int,int>> vim;
//input...
for(auto &mp:vim) cout << mp.rbegin()->first << '\n';
可用來在函數中修改不同scope變數的值
#include <iostream>
using namespace std;
void swap(int &a,int &b) {
if(a!=b) a^=b^=a^=b;
}
signed main() {
int a,b,c;
cin >> a >> b >> c;
swap(a,b);
swap(b,c);
cout << a << ' ' << b << ' ' << c << '\n';
}
//只是把兩個變數綁在一起的東西
#define ff first
#define ss second
typedef pair<int,int> pii;
pii p; // 放在全域會被預設初始化成{0,0}
pair<string,int> arr[100];
signed main() {
for(int i = 0; i < 100; i++)
cin >> arr[i].ff, arr[i].ss = i;
sort(arr, arr+100); // 會先比first,如果first一樣再比second
// make_pair(a,b)會自動推斷型別,等價於 p = pair<int,int>(a,b)
p = make_pair(arr[0].second, arr[1].second);
cout << (p.ff*p.ff + p.ss*p.ss) << '\n';
for(int i = 0; i < 100; i++) cout << arr[i].ss << ' ';
cout << '\n';
}
const int N = 1000;
int n,m;
bitset<N> graph[N],vis; //空間很小(?)和bool[]比起來差了八倍左右
void dfs(int i) {
vis[i] = true;
for(int j = 1; j <= n; j++) if(graph[i][j] && !vis[j]) dfs(j);
}
signed main() {
cin >> n >> m;
for(int i = 0; i < m; i++) {
cin >> a >> b;
graph[a][b] = graph[b][a] = 1;
}
int CC = 0;
for(int i = 1; i <= n; i++) if(!vis[i]) CC++, dfs(i);
cout << CC << '\n';
}
vector<int> fib{1,1,2,3,5,8};
map<char,int> mp{{'R',1}, {'P',2}, {'S',3}};
struct edge {int src, des, dis;};
int main() {
int a,b,d,n,m;
vector<edge> edges;
cin >> n >> m;
for(int i = 0; i < m; i++) {
cin >> a >> b >> d;
edges.push_back({a,b,d});
}
cout << max({7,1,2,2}) << '\n';
}
multiset<int> ms;
ms.insert(7);
ms.insert(1);
ms.insert(2);
ms.insert(2);
auto LR = ms.equal_range(2); // a pair, [l,r)
auto it = ms.find(6); // if cannot find returns end
ms.erase(ms.find(2));
min(a, b) / max(a, b)
min({a,b,c,...}) / max({a,b,c,...})
swap(a, b)
gcd(a, b) / __gcd(a, b) / lcm(a, b)
hypot(x, y) / sqrt(x) / pow(x, t)
floor(x) / ceil(x) / round(x)
sort(first, last[, comp]);
stable_sort(first, last[, comp]);
lower_bound(first, last, value[, comp]);
upper_bound(first, last, value[, comp]);
binary_search(first, last, value[, comp]);
max_element(first, last[, comp]);
min_element(first, last[, comp]);
nth_element(first, nth, last[, comp]);
set、map的版本請用member function
set<int> s;
s.insert(1);
s.insert(5);
s.insert(7122);
auto it = s.lower_bound(5); // return the node with key 5
int mi = *s.begin();
int mx = *prev(s.end());
// *s.rbegin()、*--s.end() also works, --operator doesn't really change the end
int have = s.count(7122);
fill(first, last, value);
iota(first, last, value);
accumulate(first, last, init[, op]);
reverse(first, last);
unique(first, last[, eq]);
next_permutation(first, last[, comp]);
prev_permutation(first, last[, comp]);
random_shuffle(first, last[, gen]);
rotate(first, pos, last)
merge(first1, last1, first2, last2, out[, comp]);
適用於函數裡面呼叫的參數和C的qsort(雖然寫法不太一樣)
bool cmp(int a, int b) {
cout << "? " << a << ' ' << b << '\n';
string verd;
cin >> verd;
return (verd == "<");
}
int id[100000];
signed main() {
int n;
cin >> n;
iota(id, id+n, 1); // id = {1,2,...i}
sort(id, id+n, cmp);
for(int i = 0; i < n; i++) cout << id[i] << " \n"[i+1==n];
}
適用在sort裡面,蠻簡潔的寫法
int n,val[100000];
signed main() {
cin >> n;
for(int i = 0; i < n; i++) cin >> v[i];
sort(v,v+n,[](int a,int b){return a > b;});
// sort(v,v+n,greater<int>());
}
相信大家都知道 int 可以做加減乘除、遞增遞減、模、位元運算、比較大小等等的運算;一個原生指標或迭代器可以 dereference,可以遞增,可能可以遞減,也可能可以做加減法運算;一個 vector 或 deque 則有下標運算 "[]"。這些我們統稱為「運算子」(operator)。 而在眾多的運算子中,還有一種 "()"。由於他的介面就像是函數一樣,因此提供 "()" 這種運算子的物件我們姑且稱作為「函數物件」,使用起來與函數幾乎沒有差別。至於函數物件的型別就稱作「函數型別」。 STL有less<T>和greater<T>等函數物件,可以把小於和大於的運算子包成函數物件供STL函式預設使用。
適用於priority_queue (雖然也可以用在普通的sort)
struct cmp {
bool operator()(string a, string b) {
return a.size() == b.size() ? a<b : a.size()<b.size();
}
}
priority_queue<string,vector<string>,cmp> pq;
signed main() {
int n,c;
string x;
cin >> n;
for(int i = 0; i < n; i++) {
cin >> c;
if(c == 0) cin >> x, pq.push(x);
else if(c == 1) cout << (pq.empty() ? pq.top() : -1) << '\n';
else if(c == 2) {
if(pq.empty()) cout << "error" << '\n';
else pq.pop();
}
}
}
幾乎全部通用
struct query {
int l,r,id;
bool operator<(const query &b) {
if(l/400 != b.l/400) return l/400 < b.l/400;
return r > b.r;
}
} Q[100000];
int n,q,v[100000];
signed main() {
cin >> n >> q;
for(int i = 0; i < n; i++) cin >> v[i];
for(int i = 0; i < q; i++) cin >> Q[i].l >> Q[i].r, Q[i].id = i;
sort(Q,Q+q);
// Mo's algo
}
大部分的STL函數傳入的比較函式都是代表「小於」
也就是如果比較函數回傳1,第一個參數就會被放比較前面
同時因為三一律,我們通常只會定義小於,其他比較運算會由小於來定義
注意在STL的設計中,對於相同的元素的比較一定要回傳0 (因為 \(x < x\) 恆為假),否則可能會RE
STL應用
離散化
假設值域足夠小,我們可以開一個BIT紀錄「有多少數字小於x」
然後從後面到前面依序查詢、插入
int BIT[1000025];
void add(int x) {
for(; x <= 1000000; x += x&-x) BIT[x]++;
}
int qry(int x) {
int r = 0;
for(; x; x -= x&-x) r += BIT[x];
return r;
}
可是值域有到\(2^{31}-1\) QQ
vector<int> arr;
map<int> mp;
int cnt;
void compress() {
mp.clear();
for(int x:arr) mp[x] = 0;
for(auto &p:mp) p.second = ++cnt;
for(int &x:arr) x = mp[x];
}
vector<int> arr, tmp;
void compress() {
tmp = arr;
sort(tmp.begin(), tmp.end());
tmp.erase(unique(tmp.begin(), tmp.end()), tmp.end());
for(int &x:arr)
x = lower_bound(tmp.begin(), tmp.end(), x) - tmp.begin() + 1;
}
offline+sort v.s rb_tree
UVa等OJ有時不允許行尾有多餘的空白,此時我們可以用下列方式簡潔的輸出(?)
int n, arr[100000];
int main() {
cin >> n;
for(int i = 0; i < n; i++) cin >> arr[i];
for(int i = 1; i < n; i++) arr[i] += arr[i-1];
for(int i = 0; i < n; i++) cout << arr[i] << " \n"[i==n-1];
}
另一個例子
#include <iostream>
using namespace std;
const int K = 20;
signed main() {
ios_base::sync_with_stdio(0), cin.tie(0);
for(int x = -K; x <= K; x++) {
for(int y = -K; y <= K; y++) {
// r^2 <= k(r-x), (x^2+x^2+kx)^2 = k^2(x^2+y^2)
cout << "#."[(x*x+y*y-x*5)*(x*x+y*y-x*5) <= 25*(x*x+y*y)];
}
cout << '\n';
}
}
double ans = exp(2);
cout << fixed << setprecision(10) << ans << '\n';
fixed是代表不要用科學記號,和scientific相對
double ans = exp(2);
printf("%.10lf\n", ans);
ios_base::sync_with_stdio(0), cin.tie(0);
// use '\n' instead of endl
freopen("in.txt","r",stdin);
freopen("out.txt","w",stdout);
加了下面這兩行就可以直接從輸出到terminal改成輸出到檔案
題敘: 給一個序列 \(<a_i>\),對每個 \(i\) 求最小的 \(j\) 使得 \(i<j\)且\(a_j \geq a_i\)
如果有兩個位置 \(x < y\) 使得 \(a_x \geq a_y\)
那麼 \(y\) 對所有在 \(x\)前面的數字都不會有影響
\(\Rightarrow\)由後往前做,要考慮的位置只有某個遞減的子序列
用一個stack儲存,維持stack內的單調性 將stack頂端與目前元素比較,不斷pop直到stack頂端大於目前元素
int n,h[1000025];
int ans[1000025];
void solve() {
stack<int> stk; // 儲存index,以便計算答案
for(int i = n-1; i >= 0; i--) {
while(!stk.empty() && h[stk.top()] >= h[i]) stk.pop();
ans[i] = (stk.empty() ? n-1 : stk.top());
stk.push(i);
}
}