函数库
目录
快速读入
int read(){
int s = 0, f = 0;
char ch = getchar();
while(!isdigit(ch)) f |= (ch == '-'), ch = getchar();
while(isdigit(ch)) s = (s << 1) + (s << 3) + ch - '0' , ch = getchar();
return f ? -s : s;
}
自定义输出
void print(__int128 x){
if(x > 9) print(x / 10);
putchar(x % 10 + '0');
}
求 \(\gcd\)
int Get_Gcd(int x, int y) { return y ? Get_Gcd(y, x % y) : x; }
exgcd
int Exgcd(int a, int b, int &x, int &y) {
if(b == 0) {
x = 1, y = 0;
return a;
}
int Gcd = Exgcd(b, a % b, x, y);
int t = x;
x = y, y = t - a / b * y;
return Gcd;
}
手写队列
struct sdeque{
int b[maxn << 1], *a = b + maxn;
int tail = 0, head = 1;
sdeque() {}
bool empty() { return tail + 1 == head;}
int size() { return tail - head + 1; }
void push_back(int x) { a[++tail] = x; }
void push_front(int x) { a[--head] = x; }
void pop_back() { --tail; }
void pop_front() { ++head; }
int back() { return a[tail]; }
int front() { return a[head]; }
}q;
高精加&乘(已封装)
// 压位高精 zhx 亲授
const int Base = 10000;
struct Bignum {
int len, a[MAXN];
Bignum () { len = 0, memset(a, 0, sizeof a); }
Bignum operator + (const Bignum &b) {
Bignum res;
res.len = max(len, b.len);
for(int i = 0; i <= res.len; ++i) {
res.a[i] += a[i] + b.a[i];
res.a[i + 1] += res.a[i] / Base;
res.a[i] %= Base;
}
if(res.a[res.len + 1]) ++ res.len;
return res;
}
Bignum operator - (const Bignum &b) {
Bignum res;
return res;
}
Bignum operator * (const Bignum &b) {
Bignum res; // a[0] ye you shu de xie fa
res.len = len + b.len + 1;
for(int i = 0; i <= len; ++i) {
for(int j = 0; j <= b.len; ++j) {
res.a[i + j] += a[i] * b.a[j];
res.a[i + j + 1] += res.a[i + j] / Base;
res.a[i + j] %= Base;
}
}
while(res.len && !res.a[res.len]) res.len --;
return res;
}
void Print() {
printf("%d", a[len]);
for(int i = len - 1; i >= 0; --i) printf("%04d", a[i]);
puts("");
}
void Input() {
char s[MAXN];
cin >> s;
int now_ = strlen(s);
len = (now_ - 1) / 4;
for(int i = 0, j = now_ - 4; i < len; ++i, j -= 4) {
// fang fa 1
// int ans = 0;
// for(int k = 0; k < 4; ++k) ans = ans * 10 + s[j + k] - '0';
// fang fa 2
sscanf(s + j, "%d", &a[i]);
s[j] = '\0';
// fang fa 3: atoi
}
sscanf(s, "%d", &a[len]);
}
};
struct Bignum{
int a[MAXN], len;
Bignum () { memset(a, 0, sizeof a), len = 0; }
Bignum operator + (const char s[]) const {
Bignum t;
int len2 = strlen(s + 1);
for(int i = 1; i <= len2; ++i) {
t.a[i] += a[i] + s[len2 - i + 1] - '0';
t.a[i + 1] += t.a[i] / 10;
t.a[i] %= 10;
}
for(int i = len2 + 1; i <= len; ++i) t.a[i] += a[i], t.a[i + 1] += t.a[i] / 10, t.a[i] %= 10;
len2 = max(len, len2);
if(t.a[len2 + 1]) ++len2;
t.len = len2;
return t;
}
Bignum operator * (const char s[]) const {
Bignum t;
int len2 = strlen(s + 1);
if(!len) { for(int i = 1; i <= len2; ++i) t.a[i] = s[len2 - i + 1] - '0'; }
for(int i = 1; i <= len; ++i)
for(int j = 1; j <= len2; ++j)
t.a[i + j - 1] += a[i] * (s[len2 - j + 1] - '0'),
t.a[i + j] += t.a[i + j - 1] / 10,
t.a[i + j - 1] %= 10;
len2 = len + len2;
while(!t.a[len2] && len2 > 1) len2--;
t.len = len2;
return t;
}
};
树状数组
namespace Bit {
int sum[MAXN];
int lowbit(int x) { return x & -x; }
void Modify(int x, int val) { for( ; x <= Cnt; x += lowbit(x)) sum[x] += val; }
int Query(int x) { int res = 0; for( ; x; x -= lowbit(x)) res += sum[x]; return res; }
}
using namespace Bit;
树剖求LCA(已封装)
namespace Cut{
struct edge{
int to, nxt;
}e[MAXN << 1];
int head[MAXN], num_edge = 0;
void add_edge(int from, int to) { e[++num_edge] = (edge){to, head[from]}, head[from] = num_edge; }
void dfs(int u, int fa) {
dep[u] = dep[fa] + 1, fath[u] = fa, siz[u] = 1;
for(int i = head[u]; i; i = e[i].nxt) {
int v = e[i].to;
if(v == fa) continue;
dfs(v, u);
siz[u] += siz[v];
if(siz[v] > siz[son[u]]) son[u] = v;
}
}
void dfs2(int u, int tp) {
dfn[u] = ++ cnt, pre[cnt] = u, top[u] = tp;
if(son[u]) dfs2(son[u], tp);
for(int i = head[u]; i; i = e[i].nxt) {
int v = e[i].to;
if(v == fath[u] || v == son[u]) continue;
dfs2(v, v);
}
}
int Get_Lca(int x, int y) {
while(top[x] != top[y]) dep[top[x]] < dep[top[y]] ? y = fath[top[y]] : x = fath[top[x]];
return dep[x] < dep[y] ? x : y;
}
}
线性筛素数(欧拉筛)
int prim[MAXN], Cnt = 0;
bool vis[MAXN];
void Init(int limit) {
for(int i = 2; i <= limit; ++i) {
if(!vis[i]) prim[++ Cnt] = i;
for(int j = 1; j <= Cnt && i * prim[j] <= limit; ++j) {
vis[i * prim[j]] = true;
if(i % prim[j] == 0) break;
}
}
}
Link-Cut-Tree
namespace LCT {
#define f fa[now_]
#define ls son[now_][0]
#define rs son[now_][1]
int fa[MAXN], son[MAXN][2];
LL siz[MAXN];
bool tag[MAXN];
void Push_up(int now_) {
if(!now_) return ;
siz[now_] = siz[ls] + siz[rs] + 1;
}
void Push_Reverse(int now_) {
if(!now_) return ;
swap(ls, rs);
tag[now_] ^= 1;
}
void Push_down(int now_) {
if(tag[now_]) Push_Reverse(ls), Push_Reverse(rs);
tag[now_] = 0;
}
bool IsRoot(int now_) { return son[f][0] != now_ && son[f][1] != now_; }
bool Whichson(int now_) { return son[f][1] == now_; }
void Rotate(int now_) {
int fa_ = f, w = Whichson(now_);
if(!IsRoot(f)) son[fa[f]][Whichson(f)] = now_;
fa[now_] = fa[f];
son[fa_][w] = son[now_][w ^ 1];
fa[son[fa_][w]] = fa_;
son[now_][w ^ 1] = fa_;
fa[fa_] = now_;
Push_up(fa_), Push_up(now_);
}
void Update(int now_) {
if(!IsRoot(now_)) Update(f);
Push_down(now_);
}
void Splay(int now_) {
Update(now_);
for( ; !IsRoot(now_); Rotate(now_)) {
if(!IsRoot(f)) Rotate(Whichson(f) == Whichson(now_) ? f : now_);
}
}
void Access(int now_) {
for(int pre_ = 0; now_; pre_ = now_, now_ = f) {
Splay(now_), rs = pre_;
Push_up(now_);
}
}
void MakeRoot(int now_) { Access(now_), Splay(now_), Push_Reverse(now_); }
int Find(int now_) {
Access(now_), Splay(now_);
while(ls) Push_down(now_), now_ = ls;
Splay(now_);
return now_;
}
void Split(int x_, int y_) { MakeRoot(x_), Access(y_), Splay(y_); }
void Link(int x_, int y_) {
MakeRoot(x_);
if(Find(y_) != x_) fa[x_] = y_;
}
void Cut(int x_, int y_) {
MakeRoot(x_);
if(Find(y_) != x_ || fa[y_] != x_ || son[y_][0]) return ;
fa[y_] = son[x_][1] = 0;
Push_up(x_);
}
int Query(int x_, int y_) {
Split(x_, y_);
return siz[y_];
}
}
矩阵乘法/快速幂
struct Matrix {
int a[MAXN][MAXN];
Matrix() { memset(a, 0, sizeof a); }
Matrix operator + (const Matrix &b) const {
Matrix res;
for(int i = 1; i <= size; ++i)
for(int j = 1; j <= size; ++j)
res.a[i][j] = a[i][j] + b.a[i][j];
return res;
}
Matrix operator - (const Matrix &b) const {
Matrix res;
for(int i = 1; i <= size; ++i)
for(int j = 1; j <= size; ++j)
res.a[i][j] = a[i][j] - b.a[i][j];
return res;
}
Matrix operator * (const Matrix &b) const {
Matrix res;
for(int k = 1; k <= size; ++k) {
for(int i = 1; i <= size; ++i) {
for(int j = 1; j <= size; ++j) {
res.a[i][j] += a[i][k] * b.a[k][j];
}
}
}
return res;
}
Matrix operator ^ (const LL x) const{
Matrix res, base;
for(int i = 1; i <= size; ++i) res.a[i][i] = 1;//初始化res矩阵
for(int i = 1; i <= size; ++i)
for(int j = 1; j <= size; ++j)
base.a[i][j] = a[i][j] % mod;
while(x) {
if(x & 1) res = res * base;
base = base * base;
x >>= 1;
}
return res;
}
};
网络流-最大流
bool bfs(){
memset(dis, -1, sizeof dis);
queue<int> q;
q.push(s);
dis[s] = 0, cur[s] = head[s];
while(!q.empty()){
int u = q.front(); q.pop();
for(int i = head[u]; i; i = e[i].nxt){
int v = e[i].to;
if(dis[v] == -1 && e[i].w){
q.push(v);
cur[v] = head[v];
dis[v] = dis[u] + 1;
if(v == t) return true;
}
}
}
return false;
}
int dfs(int u, int limit){//多路增广
if(u == t) return limit;
int flow = 0;
for(int i = cur[u]; i && flow < limit; i = e[i].nxt){//第二个条件是 流量用要够用
cur[u] = i;//当前弧优化,保证每条边只增广一次
int v = e[i].to;
if(e[i].w && dis[v] == dis[u] + 1){//如果还有残量并且v点在下一层中
int f = dfs(v, min(e[i].w, limit - flow));//向下传递的流量是边限制的流量和剩余的流量去较小值
if(!f) dis[v] = -1;//如果没有流量了,标记为-1,表示不能经过了
e[i].w -= f;//正边减流量
e[i ^ 1].w += f;//反边加流量
flow += f;//汇点流量加上获得的流量
}
}
return flow;
}
int dinic(){
int maxflow = 0, flow = 0;
while(bfs()){
while(flow = dfs(s, INF)){
maxflow += flow;
}
}
return maxflow;
}
网络流-费用流
bool spfa(){
bool flag = false;
memset(dis, 0x3f, sizeof dis);
memcpy(cur, head, sizeof head);
deque<int> q;
q.push_back(s);
dis[s] = 0, vis[s] = true;
while(!q.empty()){
int u = q.front(); q.pop_front();
vis[u] = false;
for(int i = head[u]; i; i = e[i].nxt){
int v = e[i].to;
if(e[i].w && dis[v] > dis[u] + e[i].cost){
dis[v] = dis[u] + e[i].cost;
if(!vis[v]) {
vis[v] = true;
if(!q.empty() && dis[v] < dis[q.front()]) q.push_front(v);
else q.push_back(v);
}
if(v == t) flag = true;
}
}
}
return flag;
}
int dfs(int u, int limit){
if(u == t) return limit;//遇到汇点就返回
int flow = 0;
vis[u] = true;
for(int i = cur[u]; i && flow < limit; i = e[i].nxt){//指针:可以使cur[u]随i的变化而变化
cur[u] = i;
int v = e[i].to;
if(!vis[v] && e[i].w && dis[v] == dis[u] + e[i].cost){
int f = dfs(v, min(e[i].w, limit - flow));
if(!f) dis[v] = INF;
res += f * e[i].cost;
e[i].w -= f;
e[i ^ 1].w += f;
flow += f;
// if(flow == limit) break;
}
}
vis[u] = false;
return flow;
}
int dinic(){
int maxflow = 0, flow = 0;
while(spfa()){
while(flow = dfs(s, INF)){
maxflow += flow;
}
}
return maxflow;
}
DP 求树的直径
void dfs(int u, int fa) {
// maxm[u] = minn[u] = 0;
for(int i = head[u]; i; i = e[i].nxt) {
int v = e[i].to;
if(v == fa) continue;
dfs(v, u);
int t = maxm[v] + 1;
if(t > maxm[u]) minn[u] = maxm[u], maxm[u] = t;
else if(t > minn[u]) minn[u] = t;
}
ans = max(ans, maxm[u] + minn[u]);
}