代码相关
upd on 26.3.4 代码风格由
const int maxn = 100005;
int a[maxn];
改为
const int maxn = 100000;
int a[maxn + 5];
以前代码有时间就该过来吧
缺省源
#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<ctime>
#include<vector>
#define mp make_pair
#define chkmax(a , b) a = max(a , b)
#define chkmin(a , b) a = min(a , b)
#define fo(i , x , y) for(int i = x ; i <= y ; i++)
#define go(i , x , y) for(int i = x ; i >= y ; i--)
#define local
#ifdef local
#define debug(x) cerr << #x" : " << x << ", "
#define debugn(x) cerr << #x" : " << x << "\n"
#define debugs(s) cerr << s
#define debugarr(a , n); cerr << #a" : \n"; fo(i , 1 , n) cerr << a[i] << " "; cerr << "\n";
#else
#define debug(x) "n-buna bless me."
#define debugn(x) "Nayutan bless me."
#define debugs(s) "Deco*27 bless me."
#define debugarr(a , n) "wowaka bless me."
#endif
using namespace std;
int main(){
// clock_t starttime = clock();
ios :: sync_with_stdio(0) , cin.tie(0) , cout.tie(0);
// freopen(".in" , "r" , stdin);
// freopen(".out" , "w" , stdout);
// clock_t endtime = clock();
// double elapsed = static_cast<double>(endtime - starttime) / CLOCKS_PER_SEC;
// debugn(elapsed);
}
数据结构
树状数组
const int maxn = 100000;
struct Fenwick_Tree{
private:
int t[maxn + 5];
int lowbit(int x){
return x & -x;
}
public:
void updata(int x , int v){
for(int i = x ; i <= n ; i += lowbit(i))
t[i] += v;
}
int query(int x){
int ans = 0;
for(int i = x ; i ; i -= lowbit(i))
ans += t[i];
return ans;
}
int query(int l , int r){
return query(r) - query(l - 1);
}
};
线段树
从之前普通的版本改为动态开点
struct node{
friend node operator + (const node a , const node b){
}
};
struct Segment_Tree{
private:
int cnt , ls[maxn * 2 + 5] , rs[maxn * 2 + 5];
int lazy[maxn * 2 + 5];
node t[maxn * 2 + 5];
void modify(int v1 , int l , int r , int k){
}
void pushdown(int l , int r , int k){
int mid = (l + r) / 2;
if(ls[k] == 0) ls[k] = build(l , mid);
if(rs[k] == 0) rs[k] = build(mid + 1 , r);
modify(lazy[k] , l , mid , ls[k]);
modify(lazy[k] , mid + 1 , r , rs[k]);
lazy[k] = 0;
}
public:
int build(int l , int r){
int k = ++cnt;
// init t[k] and lazy[k]
return k;
}
void update(int L , int R , int v1 , int l , int r , int k){
if(L > R) return;
if(L <= l and r <= R){
modify(v1 , l , r , k);
return;
}
pushdown(l , r , k);
int mid = (l + r) / 2;
if(L <= mid) update(L , R , v1 , l , mid , ls[k]);
if(mid + 1 <= R) update(L , R , v1 , mid + 1 , r , rs[k]);
t[k] = t[ls[k]] + t[rs[k]];
}
node query(int L , int R , int l , int r , int k){
if(L <= l and r <= R) return t[k];
pushdown(l , r , k);
int mid = (l + r) / 2;
if(L <= mid){
node ans = query(L , R , l , mid , ls[k]);
if(mid + 1 <= R) return ans + query(L , R , mid + 1 , r , rs[k]);
else return ans;
}
else return query(L , R , mid + 1 , r , rs[k]);
}
}tr;
可持久化线段树
const int maxn = 100000;
const int maxp = 100000;
const int maxnode = maxp * 2 + maxn * 20 + 5;
struct node{
long long sump , suml;
friend node operator + (const node a , const node b){
return {a.sump + b.sump , a.suml + b.suml};
}
};
struct Segment_Tree{
private:
int cnt , ls[maxnode] , rs[maxnode];
node t[maxnode];
void modify(int L , int l , int r , int k){
t[k].suml += L;
t[k].sump = t[k].suml * l;
}
public:
int build(int l , int r){
int k = ++cnt;
// init t[k] and lazy[k]
return k;
}
int update(int p , int L , int l , int r , int k){
// debug(p) , debug(L) , debug(l) , debug(r) , debugn(k);
int k2 = build(l , r);
t[k2] = t[k];
ls[k2] = ls[k] , rs[k2] = rs[k];
if(l == r){
modify(L , p , p , k2);
return k2;
}
int mid = (l + r) / 2;
if(p <= mid){
if(ls[k] == 0) ls[k] = build(l , mid);
ls[k2] = update(p , L , l , mid , ls[k]);
}
else{
if(rs[k] == 0) rs[k] = build(mid + 1 , r);
rs[k2] = update(p , L , mid + 1 , r , rs[k]);
}
t[k2] = t[ls[k2]] + t[rs[k2]];
return k2;
}
long long query(long long L , int l , int r , int k){
// debug(l) , debug(r) , debugn(k);
if(l == r){
if(t[k].suml < L) return -1;
else return L * l;
}
int mid = (l + r) / 2;
if(t[ls[k]].suml >= L) return query(L , l , mid , ls[k]);
else{
long long p2 = query(L - t[ls[k]].suml , mid + 1 , r , rs[k]);
if(p2 == -1) return -1;
return t[ls[k]].sump + p2;
}
}
}tr;
int rt[maxp + 5];
线段树其他
动态开点、权值线段树的合并,支持单点修改,线段树二分以查询 lower_bound
struct Segment_Tree{
int cnt , ls[maxn * 20] , rs[maxn * 20];
struct node{
int sum , mx;
}t[maxn * 20];
node pushup(node a , node b){
node ans = {a.sum + b.sum , max(a.mx , b.mx)};
return ans;
}
int build(){
return ++cnt;
}
void updata(int x , int v , int l , int r , int k){
if(l == r){
t[k].sum += v;
if(t[k].sum) t[k].mx = l;
else t[k].mx = 0;
return;
}
int mid = (l + r) / 2;
if(x <= mid){
if(ls[k] == 0) ls[k] = ++cnt;
updata(x , v , l , mid , ls[k]);
}
else{
if(rs[k] == 0) rs[k] = ++cnt;
updata(x , v , mid + 1 , r , rs[k]);
}
t[k] = pushup(t[ls[k]] , t[rs[k]]);
}
int query(int x , int l , int r , int k){
// cerr << x << " " << l << " " << r << " " << k << "\n";
if(r < x) return t[k].mx;
if(l == r) return 0;
int mid = (l + r) / 2;
if(mid + 1 < x) return max(query(x , l , mid , ls[k]) , query(x , mid + 1 , r , rs[k]));
else return query(x , l , mid , ls[k]);
}
int merge(int l , int r , int k1 , int k2){
if(min(k1 , k2) == 0) return k1 + k2;
if(l == r){
t[k1].sum += t[k2].sum;
if(t[k1].sum) t[k1].mx = l;
else t[k1].mx = 0;
return k1;
}
int mid = (l + r) / 2;
ls[k1] = merge(l , mid , ls[k1] , ls[k2]);
rs[k1] = merge(mid + 1 , r , rs[k1] , rs[k2]);
t[k1] = pushup(t[ls[k1]] , t[rs[k1]]);
return k1;
}
}tr;
树套树
树状数组套动态开点线段树,维护单点加,矩阵查询
struct Segment_Tree{
private:
int cnt , ls[maxn * 80] , rs[maxn * 80];
long long t[maxn * 80];
public:
int build(int l , int r){
int k = ++cnt;
t[k] = 0;
return k;
}
void update(int x , int v1 , int l , int r , int k){
if(l == r){
t[k] += v1;
return;
}
int mid = (l + r) / 2;
if(x <= mid){
if(ls[k] == 0) ls[k] = build(l , mid);
update(x , v1 , l , mid , ls[k]);
}
else{
if(rs[k] == 0) rs[k] = build(mid + 1 , r);
update(x , v1 , mid + 1 , r , rs[k]);
}
t[k] = t[ls[k]] + t[rs[k]];
}
long long query(int L , int R , int l , int r , int k){
if(k == 0) return 0;
if(L <= l and r <= R) return t[k];
int mid = (l + r) / 2;
if(L <= mid){
long long ans = query(L , R , l , mid , ls[k]);
if(mid + 1 <= R) return ans + query(L , R , mid + 1 , r , rs[k]);
else return ans;
}
else return query(L , R , mid + 1 , r , rs[k]);
}
}tr;
struct Fenwick_Tree{
private:
int rt[maxn + 5];
int lowbit(int x){
return x & -x;
}
public:
void init(){
fo(i , 1 , n + 1) rt[i] = tr.build(1 , n + 1);
}
void update(int x , int y , int v){
if(x > n + 1 or y > n + 1) return;
for(int i = x ; i <= n + 1 ; i += lowbit(i))
tr.update(y , v , 1 , n + 1 , rt[i]);
}
int query(int x , int l , int r){
int ans = 0;
for(int i = x ; i ; i -= lowbit(i))
ans += tr.query(l , r , 1 , n + 1 , rt[i]);
return ans;
}
}tr2;
平衡树
无旋 treap
#include<ctime>
#include<random>
#define mp make_pair
const int maxn = 100000;
mt19937 rd(time(0));
struct Treap{
private:
int rt , cnt , num[maxn + 5] , siz[maxn + 5] , pri[maxn + 5] , ls[maxn + 5] , rs[maxn + 5];
int build(int x){
cnt++;
num[cnt] = x , siz[cnt] = 1 , pri[cnt] = rd();
ls[cnt] = rs[cnt] = 0;
return cnt;
}
void pushup(int k){
siz[k] = siz[ls[k]] + siz[rs[k]] + 1;
}
int merge(int k1 , int k2){
if(min(k1 , k2) == 0) return max(k1 , k2);
if(pri[k1] > pri[k2]){
rs[k1] = merge(rs[k1] , k2);
pushup(k1);
return k1;
}
else{
ls[k2] = merge(k1 , ls[k2]);
pushup(k2);
return k2;
}
}
pair<int , int> split_val(int k , int key){
if(k == 0) return mp(0 , 0);
if(num[k] <= key){
pair<int , int> tmp = split_val(rs[k] , key);
rs[k] = tmp.first;
pushup(k);
return mp(k , tmp.second);
}
else{
pair<int , int> tmp = split_val(ls[k] , key);
ls[k] = tmp.second;
pushup(k);
return mp(tmp.first , k);
}
}
pair<int , int> split_siz(int k , int key){
if(k == 0) return mp(0 , 0);
if(siz[ls[k]] + 1 <= key){
pair<int , int> tmp = split_siz(rs[k] , key - siz[ls[k]] - 1);
rs[k] = tmp.first;
pushup(k);
return mp(k , tmp.second);
}
else{
pair<int , int> tmp = split_siz(ls[k] , key);
ls[k] = tmp.second;
pushup(k);
return mp(tmp.first , k);
}
}
public:
void init(){
rt = cnt = 0;
}
void insert(int x){
int k2 = build(x);
pair<int , int> tmp = split_val(rt , x);
int k1 = tmp.first , k3 = tmp.second;
rt = merge(k1 , merge(k2 , k3));
}
void del(int x){
pair<int , int> tmp = split_val(rt , x - 1);
int k1 = tmp.first , k23 = tmp.second;
tmp = split_siz(k23 , 1);
int k2 = tmp.first , k3 = tmp.second;
rt = merge(k1 , k3);
}
int rank(int x){
pair<int , int> tmp = split_val(rt , x - 1);
int k1 = tmp.first , k2 = tmp.second;
int ans = siz[k1] + 1;
rt = merge(k1 , k2);
return ans;
}
int query(int x){
pair<int , int> tmp = split_siz(rt , x - 1);
int k1 = tmp.first , k23 = tmp.second;
tmp = split_siz(k23 , 1);
int k2 = tmp.first , k3 = tmp.second;
int ans = num[k2];
rt = merge(k1 , merge(k2 , k3));
return ans;
}
int pre(int x){
pair<int , int> tmp = split_val(rt , x - 1);
int k12 = tmp.first , k3 = tmp.second;
tmp = split_siz(k12 , siz[k12] - 1);
int k1 = tmp.first , k2 = tmp.second;
int ans = num[k2];
rt = merge(k1 , merge(k2 , k3));
return ans;
}
int suf(int x){
pair<int , int> tmp = split_val(rt , x);
int k1 = tmp.first , k23 = tmp.second;
tmp = split_siz(k23 , 1);
int k2 = tmp.first , k3 = tmp.second;
int ans = num[k2];
rt = merge(k1 , merge(k2 , k3));
return ans;
}
};
有旋 treap
mt19937 rd(time(0));
struct Treap{
private:
int tot;
int ls[maxn + 5] , rs[maxn + 5] , num[maxn + 5] , cnt[maxn + 5] , siz[maxn + 5] , pri[maxn + 5];
void pushup(int k){
siz[k] = siz[ls[k]] + siz[rs[k]] + cnt[k];
}
int rrotate(int k){
int rt = ls[k];
ls[k] = rs[rt];
rs[rt] = k;
pushup(k) , pushup(rt);
return rt;
}
int lrotate(int k){
int rt = rs[k];
rs[k] = ls[rt];
ls[rt] = k;
pushup(k) , pushup(rt);
return rt;
}
public:
int insert(int k , int x){
debug(k) , debugn(x);
if(k == 0){
k = ++tot;
num[k] = x , cnt[k] = 1 , siz[k] = 1 , pri[k] = rd();
return k;
}
if(x == num[k])
cnt[k]++ , pushup(k);
else if(x < num[k]){
ls[k] = insert(ls[k] , x);
pushup(k);
if(pri[ls[k]] > pri[k]) k = rrotate(k);
}
else{
rs[k] = insert(rs[k] , x);
pushup(k);
if(pri[rs[k]] > pri[k]) k = lrotate(k);
}
return k;
}
int del(int k , int x){
debugs("del:") , debug(k) , debugn(num[k]);
if(num[k] == x){
if(cnt[k] > 1){
cnt[k]--;
}
else if(min(ls[k] , rs[k]) == 0) return ls[k] + rs[k];
else if(pri[ls[k]] > pri[rs[k]]){
k = rrotate(k);
rs[k] = del(rs[k] , x);
}
else{
k = lrotate(k);
ls[k] = del(ls[k] , x);
}
}
else if(x < num[k]){
ls[k] = del(ls[k] , x);
}
else{
rs[k] = del(rs[k] , x);
}
pushup(k);
return k;
}
int getrank(int k , int x){
if(k == 0) return 1;
if(x == num[k]) return siz[ls[k]] + 1;
if(x < num[k]) return getrank(ls[k] , x);
else return siz[ls[k]] + cnt[k] + getrank(rs[k] , x);
}
int getnum(int k , int rank){
debug(k) , debug(num[k]) , debugn(rank);
debug(num[ls[k]]) , debugn(num[rs[k]]);
if(k == 0) return -inf;
if(rank <= siz[ls[k]]) return getnum(ls[k] , rank);
if(rank <= siz[ls[k]] + cnt[k]) return num[k];
return getnum(rs[k] , rank - siz[ls[k]] - cnt[k]);
}
int getpre(int k , int x){
if(k == 0) return -inf;
if(num[k] < x){
int ans = getpre(rs[k] , x);
if(ans != -inf) return ans;
else return num[k];
}
else return getpre(ls[k] , x);
}
int getnxt(int k , int x){
if(k == 0) return -inf;
if(num[k] > x){
int ans = getnxt(ls[k] , x);
if(ans != -inf) return ans;
else return num[k];
}
else return getnxt(rs[k] , x);
}
};
ST 表
\([i - 2^j + 1 , i]\) 的 st 表,可实现在线插入
int lg[maxn + 5];
void init(){
lg[2] = 1;
fo(i , 3 , maxn + 1)
lg[i] = lg[i / 2] + 1;
}
struct Sparse_Table{
private:
int st[18][maxn + 5];
public:
void ins(int id , int num){
st[0][id] = num;
for(int j = 1 ; id - (1 << j) + 1 >= 1 ; j++){
st[j][id] = max(st[j - 1][id] , st[j - 1][id - (1 << j - 1)]);
}
}
int ask(int l , int r){
if(l > r) return -inf;
int k = lg[r - l + 1];
return max(st[k][r] , st[k][l + (1 << k) - 1]);
}
void clear(){
fo(j , 0 , 17)
fo(i , 1 , n)
st[j][i] = 0;
}
}
李超线段树
现在只写了支持全局线段插入,区间插入的以后再写
struct func{
long long a , b;
};
class lichao{
private:
func t[maxn << 2];
long long f(int x , func a){
return a.a * x + a.b;
}
public:
void build(int l , int r , int k){
t[k] = {0 , 0};
if(l == r) return;
int mid = (l + r) / 2;
build(l , mid , k << 1) , build(mid + 1 , r , k << 1 | 1);
}
void insert(func x , int l , int r , int k){
int mid = (l + r) / 2;
if(f(mid , t[k]) < f(mid , x)) swap(t[k] , x);
if(l == r) return;
if(x.a < t[k].a) insert(x , l , mid , k << 1);
else insert(x , mid + 1 , r , k << 1 | 1);
}
long long query(int x , int l , int r , int k){
if(l == r) return f(x , t[k]);
int mid = (l + r) / 2;
long long ans = f(x , t[k]);
if(x <= mid) return max(ans , query(x , l , mid , k << 1));
else return max(ans , query(x , mid + 1 , r , k << 1 | 1));
}
};
字符串
哈希
const int maxl = 1000000;
const int base1 = 131;
const int mod1 = 1000000007;
const int base2 = 233;
const int mod2 = 998244353;
int powbase1[maxl + 5] , powbase2[maxl + 5];
void init(){
powbase1[0] = 1;
fo(i , 1 , maxl) powbase1[i] = 1ll * powbase1[i - 1] * base1 % mod1;
powbase2[0] = 1;
fo(i , 1 , maxl) powbase2[i] = 1ll * powbase2[i - 1] * base2 % mod2;
}
struct mystring{
private:
string s;
int len;
pair<int , int> hsh[maxl + 5];
void solve(){
fo(i , 1 , len){
hsh[i].first = (1ll * hsh[i - 1].first * base1 % mod1 + s[i]) % mod1;
hsh[i].second = (1ll * hsh[i - 1].second * base2 % mod2 + s[i]) % mod2;
}
}
public:
void read(){
cin >> s;
len = s.size();
s = " " + s;
solve();
}
void init(string input){
len = input.size();
s = " " + input;
solve();
}
pair<int , int> gethash(int l , int r){
int ans1 = hsh[r].first;
int tmp1 = 1ll * hsh[l - 1].first * powbase1[r - l + 1] % mod1;
ans1 = (ans1 - tmp1 + mod1) % mod1;
int ans2 = hsh[r].second;
int tmp2 = 1ll * hsh[l - 1].second * powbase2[r - l + 1] % mod2;
ans2 = (ans2 - tmp2 + mod2) % mod2;
return mp(ans1 , ans2);
}
pair<int , int> gethash(){
return hsh[len];
}
};
KMP
string s;
int fail[maxl + 5];
for(int i = 2 , j = 0 ; i <= n ; i++){
while(j and s[j + 1] != s[i]) j = fail[j];
if(s[j + 1] == s[i]) j++;
fail[i] = j;
}
SA
int rk[maxl + 5] , sa[maxl + 5] , oldrk[maxl + 5] , id[maxl + 5] , cnt[maxl + 5] , height[maxl + 5];
void getSA(){
int m = 128 , p = 0;
fo(i , 1 , n) cnt[rk[i] = s[i]]++;
fo(i , 1 , m) cnt[i] += cnt[i - 1];
fo(i , 1 , n) sa[cnt[rk[i]]--] = i;
for(int w = 1 ; ; w *= 2 , m = p){
int cur = 0;
fo(i , n - w + 1 , n) id[++cur] = i;
fo(i , 1 , n)
if(sa[i] > w)
id[++cur] = sa[i] - w;
memset(cnt , 0 , sizeof(cnt));
fo(i , 1 , n) cnt[rk[i]]++;
fo(i , 1 , m) cnt[i] += cnt[i - 1];
go(i , n , 1) sa[cnt[rk[id[i]]]--] = id[i];
memcpy(oldrk , rk , sizeof(rk));
p = 0;
fo(i , 1 , n){
if(oldrk[sa[i]] == oldrk[sa[i - 1]] and oldrk[sa[i] + w] == oldrk[sa[i - 1] + w])
rk[sa[i]] = p;
else rk[sa[i]] = ++p;
}
if(p == n) break;
}
int k = 0;
fo(i , 1 , n){
if(k) k--;
while(s[i + k] == s[sa[rk[i] - 1] + k]) k++;
height[rk[i]] = k;
}
}
AC 自动机
int cnt = 1;
struct node{
int son[maxv + 5] , fail;
int len;
bool flag;
}trie[maxl + 5];
void insert(string s){
int u = 1 , len = s.size() - 1;
fo(i , 1 , len){
int c = s[i] - 'a' + 1;
if(trie[u].son[c] == 0) trie[u].son[c] = ++cnt;
u = trie[u].son[c];
}
trie[u].len = len;
trie[u].flag = true;
}
void getfail(){
fo(i , 1 , 26) trie[0].son[i] = 1;
queue<int> q;
q.push(1);
while(q.size()){
int u = q.front();
q.pop();
int fail = trie[u].fail;
fo(i , 1 , 26){
int& v = trie[u].son[i];
if(v == 0){
v = trie[fail].son[i];
continue;
}
trie[v].fail = trie[fail].son[i];
q.push(v);
}
}
}
图、树相关
点分树
vector<int> e[maxn + 5];
int siz[maxn + 5];
bool vis[maxn + 5];
int get_root(int u , int sum , int fa){
int ans = -1;
siz[u] = 1;
bool flag = true;
for(int v : e[u]){
if(v == fa) continue;
if(vis[v]) continue;
int res = get_root(v , sum , u);
if(res != -1) ans = res;
if(siz[v] * 2 > sum) flag = false;
siz[u] += siz[v];
}
if(ans != -1) return ans;
if(flag and (sum - siz[u]) * 2 <= sum) return u;
return -1;
}
void solve(int rt , int sum){
vis[rt] = true;
for(int v : e[rt]){
if(vis[v]) continue;
int sumv = (siz[v] < siz[rt] ? siz[v] : sum - siz[rt]);
solve(get_root(v , sumv , 0) , sumv);
}
}
重链剖分
有边权版本
struct Decomposition{
int siz[maxn + 5] , fa[maxn + 5] , dep[maxn + 5] , son[maxn + 5] , top[maxn + 5] , idx , dfn[maxn + 5];
long long dis[maxn + 5];
void dfs1(int u , int f){
siz[u] = 1 , fa[u] = f , dep[u] = dep[f] + 1;
for(node x : e[u]){
int v = x.v;
if(v == f) continue;
dis[v] = dis[u] + x.w;
dfs1(v , u);
siz[u] += siz[v];
if(siz[v] > siz[son[u]]) son[u] = v;
}
}
void dfs2(int u , int tp){
top[u] = tp;
dfn[u] = ++idx;
if(son[u]) dfs2(son[u] , tp);
for(node x : e[u]){
int v = x.v;
if(v == fa[u]) continue;
if(v == son[u]) continue;
dfs2(v , v);
}
}
int lca(int u , int v){
while(top[u] != top[v]){
if(dep[top[u]] < dep[top[v]]) swap(u , v);
u = fa[top[u]];
}
if(dep[u] < dep[v]) swap(u , v);
return v;
}
long long get_dis(int u , int v){
int f = lca(u , v);
return dis[u] + dis[v] - dis[f] * 2;
}
};
tarjan
int dfncnt , dfn[maxn + 5] , low[maxn + 5];
bool in_stack[maxn + 5];
int tp , st[maxn + 5];
int sc;
vector<int> scc[maxn + 5];
void tarjan(int u){
dfn[u] = low[u] = ++dfncnt;
st[++tp] = u , in_stack[u] = true;
for(int v : e[u]){
if(dfn[v] == 0){
tarjan(v);
low[u] = min(low[u] , low[v]);
}
else if(in_stack[v]){
low[u] = min(low[u] , dfn[v]);
}
}
if(low[u] != dfn[u]) return;
sc++;
while(true){
int v = st[tp];
in_stack[v] = false;
scc[sc].push_back(v);
tp--;
if(v == u) break;
}
}
fo(u , 1 , n){
if(dfn[u] == 0) tarjan(u);
}
网络流
最大流
struct Dinic{
private:
const long long inf = 1000000000000000000;
int n , s , t;
struct node{
int v , rev;
long long w;
};
vector<node> e[maxn + 5];
int k[maxn + 5] , dep[maxn + 5];
queue<int> q;
bool bfs(){
fo(i , 1 , n) dep[i] = -1;
dep[s] = 1;
while(q.size()) q.pop();
q.push(s);
while(q.size()){
int u = q.front();
q.pop();
for(node x : e[u]){
int v = x.v;
long long w = x.w;
if(dep[v] != -1 or w == 0) continue;
dep[v] = dep[u] + 1;
if(v == t) return true;
q.push(v);
}
}
return false;
}
long long dfs(int u , long long flow){
if(u == t) return flow;
long long used = 0;
for(int &i = k[u] ; i < e[u].size() ; i++){
int v = e[u][i].v;
int rev = e[u][i].rev;
long long& w = e[u][i].w;
if(dep[v] <= dep[u] or w == 0) continue;
long long flowv = dfs(v , min(flow - used , w));
if(flowv == 0) continue;
w -= flowv;
e[v][rev].w += flowv;
used += flowv;
if(used == flow) break;
}
return used;
}
public:
void init(int inputn , int inputs , int inputt){
n = inputn , s = inputs , t = inputt;
fo(i , 1 , n) e[i].clear();
}
void add(int u , int v , long long w){
int sizu = e[u].size();
int sizv = e[v].size();
e[u].push_back({v , sizv , w});
e[v].push_back({u , sizu , 0});
}
long long maxflow(){
long long ans = 0;
while(bfs()){
fo(i , 1 , n) k[i] = 0;
long long flow = dfs(s , inf);
while(flow > 0){
ans += flow;
flow = dfs(s , inf);
}
}
return ans;
}
}qwq;
最小费用流
#include<queue>
#include<vector>
const int maxnode = 5000;
const long long inf = 1000000000;
struct Dinic_mincost{
private:
int n , s , t;
struct node{
int v , rev;
long long w , cost;
};
vector<node> e[maxnode + 5];
queue<int> q;
bool vis[maxnode + 5];
long long dep[maxnode + 5];
bool spfa(){
fo(i , 1 , n) dep[i] = inf , vis[i] = false;
while(q.size()) q.pop();
dep[s] = 0 , vis[s] = true;
q.push(s);
while(q.size()){
int u = q.front();
q.pop();
vis[u] = 0;
for(node x : e[u]){
int v = x.v;
long long w = x.w , cost = x.cost;
if(w == 0) continue;
if(dep[v] <= dep[u] + cost) continue;
dep[v] = dep[u] + cost;
if(vis[v] == true) continue;
vis[v] = true;
q.push(v);
}
}
return (dep[t] < inf);
}
int k[maxnode + 5];
long long dfs(int u , long long flow , long long& mincost){
if(u == t) return flow;
long long used = 0;
vis[u] = 1;
for(int& i = k[u] ; i < e[u].size() ; i++){
int v = e[u][i].v , rev = e[u][i].rev;
long long& w = e[u][i].w , cost = e[u][i].cost;
if(w == 0 or dep[v] != dep[u] + cost or vis[v]) continue;
long long flowv = dfs(v , min(flow - used , w) , mincost);
if(flowv == 0) continue;
w -= flowv;
e[v][rev].w += flowv;
mincost += flowv * cost;
used += flowv;
if(used == flow) break;
}
vis[u] = 0;
return used;
}
public:
void init(int inputn , int inputs , int inputt){
n = inputn , s = inputs , t = inputt;
fo(i , 1 , n) e[i].clear();
}
void add(int u , int v , long long w , long long cost){
int sizu = e[u].size();
int sizv = e[v].size();
e[u].push_back({v , sizv , w , cost});
e[v].push_back({u , sizu , 0 , -cost});
}
pair<long long , long long> max_flow(){
long long maxflow = 0 , mincost = 0;
while(spfa()){
fo(i , 1 , n) k[i] = 0;
long long flow = dfs(s , inf , mincost);
while(flow != 0){
maxflow += flow;
flow = dfs(s , inf , mincost);
}
}
return mp(maxflow , mincost);
}
}qwq;
数学
组合数学
int fac[maxn + 5] , inv[maxn + 5];
int qpow(int a , int b){
if(b == 0) return 1;
int ans = qpow(a , b / 2);
if(b % 2) return 1ll * ans * ans % mod * a % mod;
else return 1ll * ans * ans % mod;
}
// 记得一定要调用 init 喵,没调用全部草饲喵
void init(){
fac[0] = 1;
fo(i , 1 , maxn) fac[i] = 1ll * fac[i - 1] * i % mod;
inv[maxn] = qpow(fac[maxn] , mod - 2);
go(i , maxn - 1 , 0) inv[i] = 1ll * inv[i + 1] * (i + 1) % mod;
}
int getinv(int a){
return 1ll * inv[a] * fac[a - 1] % mod;
}
int C(int n , int m){
return 1ll * fac[n] * inv[n - m] % mod * inv[m] % mod;
}
数论
int gcd(int a , int b){
if(b == 0) return a;
return gcd(b , a % b);
}
// 欧拉筛求 mu
int mu[maxn + 5];
bool notprime[maxn + 5];
vector<int> prime;
void seive(){
mu[1] = 1;
fo(i , 2 , maxn){
if(notprime[i] == false){
mu[i] = -1;
prime.push_back(i);
}
for(int p : prime){
if(1ll * p * i > maxn) break;
notprime[p * i] = true;
if(i % p == 0){
mu[p * i] = 0;
break;
}
mu[p * i] = -mu[i];
}
}
}
其他小trick
创建 \(n\) 行 \(m\) 列的矩阵
vector<vector<int>> dp(n + 5 , vector<int>(m + 5 , 0));
STL 的迭代器
set<node> :: iterator it = s.begin();
// 有一次将 set<node> :: iterator it 写成 set<int> :: iterator it 看了好久
// 当然你也可以放心用 auto
auto it = s.begin();
// 尽管 map set 不是线性的,但你仍然可以
it-- , it++;
// 来找它的前后继
priority_queue 的使用
priority_queue<node> q;
// 首先不要拼错,其次默认为大根堆
// 如果要小根堆
priority_queue<node , vector<node> , greater<node> > q;
// vector 表明实现方式, 即 node 是存在 vector 中的
// greater 与 less 相对, 表明从大到小
// 需要重载 > 号
在字符串后加字符
string s;
s = s + "I love Elaina"; // O(n)
s += "I love Elaina"; // O(1)
随机数
#include<ctime>
#include<random>
mt19937 rd(time(0));
shuffle(a + 1 , a + n + 1 , rd);
// 将 a[1 , n] 随机打乱,rd为提供的随机化函数

浙公网安备 33010602011771号