vector<int> fa(n + 1); //扩展域并查集注意开n*3+1iota(fa.begin(), fa.end(), 0);
// 带权并查集则同时更新d[x],siz[x]
function<int(int)> find = [&](int x) { return x == fa[x] ? x : fa[x] = find(fa[x]); };
auto unite = [&](int x, int y) { fa[find(x)] = find(y); };
线段树
voidrefresh(int p){ sum[p] = sum[ls[p]] + sum[rs[p]]; }
//动态开点权值线段树intadd(int p, int l, int r, int x){
if (!p) p = ++tot;
if (l == r) { sum[p]++; return p; }
int mid = (l + r) >> 1;
x <= mid ? ls[p] = add(ls[p], l, mid, x) : rs[p] = add(rs[p], mid + 1, r, x);
returnrefresh(p), p;
}
//线段树合并intmerge(int p, int q, int l, int r){
if (!p) return q;
if (!q) return p;
if (l == r) { sum[p] += sum[q]; return p; }
int mid = (l + r) >> 1;
if (l <= mid) ls[p] = merge(ls[p], ls[q], l, mid);
if (r > mid) rs[p] = merge(rs[p], rs[q], mid + 1, r);
returnrefresh(p), p;
}
//线段树上二分intask(int p, int l, int r, int k){
if (l == r) return l;
int mid = (l + r) >> 1;
if (sum[ls[p]] >= k) returnask(ls[p], l, mid, k);
elsereturnask(rs[p], mid + 1, r, k - sum[ls[p]]);
}
吉老师线段树
structseg {
int l, r;
int vmax, vmaxh, vsec, mxcnt, sum;
int tmax, telse, tmaxh, telseh;
} t[MAXN << 2];
#define ls p << 1#define rs p << 1 | 1#define mid ((t[p].l + t[p].r) >> 1)voidrefresh(int p){
t[p].vmax = max(t[ls].vmax, t[rs].vmax);
t[p].vmaxh = max(t[ls].vmaxh, t[rs].vmaxh);
t[p].sum = t[ls].sum + t[rs].sum;
if (t[ls].vmax == t[rs].vmax) {
t[p].vsec = max(t[ls].vsec, t[rs].vsec);
t[p].mxcnt = t[ls].mxcnt + t[rs].mxcnt;
} elseif (t[ls].vmax > t[rs].vmax) {
t[p].vsec = max(t[ls].vsec, t[rs].vmax);
t[p].mxcnt = t[ls].mxcnt;
} else {
t[p].vsec = max(t[ls].vmax, t[rs].vsec);
t[p].mxcnt = t[rs].mxcnt;
}
}
voidbuild(int p, int l, int r){
t[p].l = l, t[p].r = r;
if (l == r) {
cin >> t[p].vmaxh;
t[p].sum = t[p].vmax = t[p].vmaxh;
t[p].vsec = -INF;
t[p].mxcnt = 1;
return;
}
build(ls, l, mid), build(rs, mid + 1, r);
refresh(p);
}
voidaddtag(int p, int tmax, int tmaxh, int telse, int telseh){
t[p].sum += t[p].mxcnt * tmax + (t[p].r - t[p].l + 1 - t[p].mxcnt) * telse;
t[p].vmaxh = max(t[p].vmaxh, t[p].vmax + tmaxh);
t[p].tmaxh = max(t[p].tmaxh, t[p].tmax + tmaxh);
t[p].telseh = max(t[p].telseh, t[p].telse + telseh);
t[p].vmax += tmax;
t[p].tmax += tmax;
t[p].telse += telse;
if (t[p].vsec != -INF) t[p].vsec += telse;
}
voidpushdown(int p){
int tmp = max(t[ls].vmax, t[rs].vmax);
if (t[ls].vmax == tmp) addtag(ls, t[p].tmax, t[p].tmaxh, t[p].telse, t[p].telseh);
elseaddtag(ls, t[p].telse, t[p].telseh, t[p].telse, t[p].telseh);
if (t[rs].vmax == tmp) addtag(rs, t[p].tmax, t[p].tmaxh, t[p].telse, t[p].telseh);
elseadd_tag(rs, t[p].telse, t[p].telseh, t[p].telse, t[p].telseh);
t[p].tmax = t[p].tmaxh = t[p].telse = t[p].telseh = 0;
}
voidcadd(int p, int l, int r, int val){
if (l <= t[p].l && t[p].r <= r) {
add_tag(p, val, val, val, val);
return;
}
pushdown(p);
if (l <= mid) cadd(ls, l, r, val);
if (r > mid) cadd(rs, l, r, val);
refresh(p);
}
voidcmin(int p, int l, int r, int val){
if (val >= t[p].vmax) return;
if (l <= t[p].l && t[p].r <= r && val > t[p].vsec) {
add_tag(p, val - t[p].vmax, val - t[p].vmax, 0, 0);
return;
}
pushdown(p);
if (l <= mid) cmin(ls, l, r, val);
if (r > mid) cmin(rs, l, r, val);
refresh(p);
}
intqsum(int p, int l, int r){
if (l <= t[p].l && t[p].r <= r) return t[p].sum;
pushdown(p);
int ans = 0;
if (l <= mid) ans += qsum(ls, l, r);
if (r > mid) ans += qsum(rs, l, r);
return ans;
}
intqmax(int p, int l, int r){
if (l <= t[p].l && t[p].r <= r) return t[p].vmax;
pushdown(p);
int ans = -INF;
if (l <= mid) ans = max(ans, qmax(ls, l, r));
if (r > mid) ans = max(ans, qmax(rs, l, r));
return ans;
}
intqmaxh(int p, int l, int r){
if (l <= t[p].l && t[p].r <= r) return t[p].vmaxh;
pushdown(p);
int ans = -INF;
if (l <= mid) ans = max(ans, qmaxh(ls, l, r));
if (r > mid) ans = max(ans, qmaxh(rs, l, r));
return ans;
}
李超树
structseg {
double k, b;
voidinit(int x0, int y0, int x1, int y1){
if (x0 == x1) k = 0, b = max(y0, y1);
else k = 1.0 * (y1 - y0) / (x1 - x0), b = y0 - k * x0;
}
} a[MAXN];
structnode {
int id;
double y;
booloperator<(const node &a) const {
if (fabs(y - a.y) < eps) return id > a.id;
return y < a.y;
}
};
//第id条直线在x处取值doublef(int id, int x){ return a[id].k * x + a[id].b; }
structsegtree {
int l, r, id;
} t[MAXN << 2];
#define ls p << 1#define rs p << 1 | 1#define mid ((t[p].l + t[p].r) >> 1)//建树build(1,1,n)voidbuild(int p, int l, int r){
t[p].l = l, t[p].r = r;
if (l == r) return;
build(ls, l, mid), build(rs, mid + 1, r);
}
voidchange(int p, int l, int r, int id){
if (l <= t[p].l && t[p].r <= r) {
if (!t[p].id) { t[p].id = id; return; }
if (t[p].l == t[p].r) {
if (f(id, t[p].l) > f(t[p].id, t[p].l)) t[p].id = id;
return;
}
if (fabs(a[id].k - a[t[p].id].k) < eps) {
if (f(id, mid) > f(t[p].id, mid)) t[p].id = id;
} elseif (a[id].k > a[t[p].id].k) {
if (f(id, mid) > f(t[p].id, mid)) change(ls, l, r, t[p].id), t[p].id = id;
elsechange(rs, l, r, id);
} else {
if (f(id, mid) > f(t[p].id, mid)) change(rs, l, r, t[p].id), t[p].id = id;
elsechange(ls, l, r, id);
}
return;
}
if (l <= mid) change(ls, l, r, id);
if (r > mid) change(rs, l, r, id);
}
node query(int p, int x){
node ans = {t[p].id, f(t[p].id, x)};
if (t[p].l == t[p].r) return ans;
returnmax(x <= mid ? query(ls, x) : query(rs, x), ans);
}
//查询x=k处编号最大的线段(可修改node operator)query(1, x).id;
//插入线段if (x0 > x1) swap(x0, x1), swap(y0, y1);
a[++cnt].init(x0, y0, x1, y1), change(1, x0, x1, cnt);
主席树 (静态区间第k小)
structsegtree { int ls, rs, sum; } t[N << 5];
// 初始化rt[0]=build(1,n)为离散化后的值域intbuild(int l, int r){
int p = ++tot;
if (l == r) return p;
int mid = l + r >> 1;
t[p].ls = build(l, mid), t[p].rs = build(mid + 1, r);
return root;
}
//插入rt[i]=update(x,1,n,rt[i-1])intupdate(int x, int l, int r, int o){
int p = ++tot;
t[p] = t[o], t[p].sum++;
if (l == r) return dir;
int mid = l + r >> 1;
if (x <= mid) t[p].ls = update(x, l, mid, t[p].ls);
else t[p].rs = update(x, mid + 1, r, t[p].rs);
return p;
}
//查询query(rt[l-1],rt[r],1,n,k)intquery(int p, int q, int l, int r, int k){
if (l == r) return l;
int mid = l + r >> 1, x = t[t[q].ls].sum - t[t[p].ls].sum;
if (k <= x) returnquery(t[p].ls, t[q].ls, l, mid, k);
elsereturnquery(t[p].rs, t[q].rs, mid + 1, r, k - x);
}
FHQ平衡树
structnode {
int siz, ls, rs, prio, val;
} t[N];
int n, m, tot, root;
intnewnode(int k){
t[++tot] = (node){1, 0, 0, rand(), k};
return tot;
}
voidrefresh(int p){ t[p].siz = t[t[p].ls].siz + t[t[p].rs].siz + 1; }
intmerge(int p, int q){
if (!p || !q) return p + q;
if (t[p].prio < t[q].prio) {
t[p].rs = merge(t[p].rs, q);
refresh(p);
return p;
}
t[q].ls = merge(p, t[q].ls);
refresh(q);
return q;
}
voidsplit(int now, int k, int &p, int &q){
if (!now) { p = q = 0; return; }
if (t[now].val <= k) p = now, split(t[now].rs, k, t[now].rs, q);
else q = now, split(t[now].ls, k, p, t[now].ls);
refresh(now);
}
intkth(int p, int k){
while (1) {
if (k <= t[t[p].ls].siz) p = t[p].ls;
elseif (k > t[t[p].ls].siz + 1) k -= t[t[p].ls].siz + 1, p = t[p].rs;
elsereturn p;
}
}
//插入整数ksplit(root, k, x, y);
root = merge(merge(x, newnode(k)), y);
//删除整数ksplit(root, k, x, z);
split(x, k - 1, x, y);
y = merge(t[y].ls, t[y].rs);
root = merge(merge(x, y), z);
//查询k的排名split(root, k - 1, x, y);
ans = t[x].siz + 1;
root = merge(x, y);
//查询排名为k的数(如果不存在,则认为是排名小于k的最大数)
ans = t[kth(root, k)].val;
//k的前驱split(root, k - 1, x, y);
ans = t[kth(x, t[x].siz)].val;
root = merge(x, y);
//k的后继split(root, k, x, y);
ans = t[kth(y, 1)].val;
root = merge(x, y);
文艺平衡树 (splay)
structSplay {
int val[N], ch[N][2], fa[N], tag[N], siz[N], root;
Splay() { root = 0; }
boolchk(int x){ return ch[fa[x]][1] == x; }
voidrefresh(int x){ siz[x] = siz[ch[x][0]] + siz[ch[x][1]] + 1; }
voidpushdown(int x){
if (tag[x]) {
if (ch[x][0]) {
tag[ch[x][0]] ^= 1;
swap(ch[ch[x][0]][0], ch[ch[x][0]][1]);
}
if (ch[x][1]) {
tag[ch[x][1]] ^= 1;
swap(ch[ch[x][1]][0], ch[ch[x][1]][1]);
}
tag[x] = 0;
}
}
voidrotate(int now){
int f = fa[now], gf = fa[f], k = chk(now), w = ch[now][k ^ 1];
fa[w] = f, ch[f][k] = w;
fa[now] = gf, ch[gf][chk(f)] = now;
fa[f] = now, ch[now][k ^ 1] = f;
refresh(f), refresh(now);
}
voidsplay(int now, int goal = 0){
while (fa[now] != goal) {
int f = fa[now], gf = fa[f];
if (gf != goal) {
if (chk(f) == chk(now)) rotate(f);
elserotate(now);
}
rotate(now);
}
if (!goal) root = now;
}
intkth(int k){
int now = root;
while (1) {
pushdown(now);
if (ch[now][0] && siz[ch[now][0]] >= k) now = ch[now][0];
elseif (siz[ch[now][0]] + 1 < k) {
k -= siz[ch[now][0]] + 1;
now = ch[now][1];
} elsereturn now;
}
}
intsplit(int l, int r){
l = kth(l), r = kth(r + 2);
splay(l), splay(r, l);
return ch[r][0];
}
voidreverse(int l, int r){
int now = split(l, r);
tag[now] ^= 1;
swap(ch[now][0], ch[now][1]);
}
intquery(int x){ return val[split(x, x)]; }
intbuild(int l, int r, int f){
if (l > r) return0;
int mid = (l + r) >> 1;
val[mid] = a[mid], fa[mid] = f;
ch[mid][0] = build(l, mid - 1, mid);
ch[mid][1] = build(mid + 1, r, mid);
refresh(mid);
return mid;
}
} T;
intmain(){
cin >> n >> m;
a[1] = a[n + 2] = -INF;
for (int i = 2; i <= n + 1; ++i) a[i] = i - 1;
T.root = T.build(1, n + 2, 0);
while (m--) {
int l = read(), r = read();
T.reverse(l, r);
}
for (int i = 1; i <= n; ++i) pintf("%d ", T.query(i));
}
左偏树
structheap { int val, fa, d, ch[2]; }t[N];
//dist大的视为左儿子,dist小的视为右儿子int& rs(int x){ return t[x].ch[t[t[x].ch[1]].d < t[t[x].ch[0]].d]; }
//插入时直接merge一个新节点,O(log n)复杂度intmerge(int x, int y){
if (!x || !y) return x | y;
if (t[x].val < t[y].val) swap(x, y);
int& rs_ref = rs(x);
rs_ref = merge(rs_ref, y);
t[rs_ref].fa = x;
t[x].d = t[rs(x)].d + 1;
return x;
}
//配合并查集维护是否在一个堆里(旧根指向新根),用数组记录是否被删除//合并代码
x = find(x), y = find(y);
if (x != y) rt[x] = rt[y] = merge(x, y);
//删除根
x = find(x);
rt[x] = rt[t[x].ch[0]] = rt[t[x].ch[1]] = merge(t[x].ch[0], t[x].ch[1]);
// 由于堆中的点会 find 到 x,所以 rt[x] 也要修改
ST表
voidpre(){ //预处理log
Logn[1] = 0, Logn[2] = 1;
for (int i = 3; i < maxn; i++) Logn[i] = Logn[i / 2] + 1;
}
// 求静态区间[l,r]最大值/最小值/gcdfor (int i = 1; i <= n; i++) f[i][0] = read();
pre();
//根据maxn确定logn=21,22..for (int j = 1; j <= logn; j++)
for (int i = 1; i + (1 << j) - 1 <= n; i++)
f[i][j] = max(f[i][j - 1], f[i + (1 << (j - 1))][j - 1]);
for (int i = 1; i <= m; i++) {
int x = read(), y = read();
int s = Logn[y - x + 1];
printf("%d\n", max(f[x][s], f[y - (1 << s) + 1][s]));
}
树状数组
#define lowbit(x) (x)&(-x)voidadd(int x, int k){ for (x <= n; x += lowbit(x)) c[x] += k; } //单点加intask(int x){ // a[1]..a[x]的和,用前缀和实现区间查询int ans = 0;
for (x > 0; x -= lowbit(x)) ans += c[x];
return ans;
}
莫队
//如果能把当前区间[l,r]的答案转移到与其相邻的区间,则可以实现O(n\sqrt(n))的复杂度voidadd(int x);
voiddel(int x);
voidsolve(){
BLOCK_SIZE = int(ceil(pow(n, 0.5)));
//l为第一关键字,r为第二关键字从小到大排序sort(querys, querys + m);
for (int i = 0; i < m; ++i) {
const query &q = querys[i];
while (l > a[i].l) add(c[--l]);
while (r < a[i].r) add(c[++r]);
while (l < a[i].l) del(c[l++]);
while (r > a[i].r) del(c[r--]);
ans[q.id] = res;
}
}
树链剖分
voiddfs1(int u){
dep[u] = dep[fa[u]] + 1;
siz[u] = 1;
int mxson = -1;
for (int i = h[u]; i; i = e[i].nxt) {
int v = e[i].v;
if (v == fa[u]) continue;
fa[v] = u;
dfs1(v);
siz[u] += siz[v]; //子树大小if (!son[u] || siz[v] > mxson) {
son[u] = v; //重儿子
mxson = siz[v];
}
}
}
voiddfs2(int u, int topf){
b[id[u] = ++dfn] = a[u];
top[u] = topf; //链顶if (!son[u]) return;
dfs2(son[u], topf);
for (int i = h[u]; i; i = e[i].nxt) {
int v = e[i].v;
if (v != fa[u] && v != son[u]) dfs2(v, v);
}
}
//树上路径+vvoidtadd(int x, int y, int v){
while (top[x] != top[y]) {
if (dep[top[x]] < dep[top[y]]) swap(x, y);
add(1, id[top[x]], id[x], v);
x = fa[top[x]];
}
if (dep[x] < dep[y]) swap(x, y);
add(1, id[y], id[x], v);
}
//树上路径求和inttquery(int x, int y){
int ans = 0;
while (top[x] != top[y]) {
if (dep[top[x]] < dep[top[y]]) swap(x, y);
ans += query(1, id[top[x]], id[x]);
x = fa[top[x]];
}
if (dep[x] < dep[y]) swap(x, y);
ans += query(1, id[y], id[x]);
return ans;
}
//子树内+vadd(1, id[x], id[x] + siz[x] - 1, k);
//子树内求和query(1, id[x], id[x] + siz[x] - 1);
原地堆化
voidheapify(int[] h) { // 从下往上遍历非叶子节点for (inti= h.length / 2 - 1; i >= 0; i--) sink(h, i);
}
voidsink(int[] h, int i) {
intn= h.length;
while (2 * i + 1 < n) {
intj=2 * i + 1; // 左儿子(因为起始下标为0所以+1)if (j + 1 < n && h[j + 1] > h[j]) j++; // 跟左右儿子中较大的交换if (h[i] >= h[j]) break; // 无法交换,递归结束
swap(h, i, j), i = j; // 交换后继续向下递归
}
}
计算几何
基本常数
constdouble eps = 1e-10;
constlongdouble PI = acos(-1.0);
vector<Point> ConvexHell(vector<Point> &p){
sort(p.begin(), p.end());
p.erase(unique(p.begin(), p.end()), p.end());
int n = p.size(), m = 0;
vector<Point> stk(n + 1);
for (int i = 0;i < n;i++) {
while (m > 1 && Cross(stk[m - 1] - stk[m - 2], p[i] - stk[m - 2]) <= 0) m--;
stk[m++] = p[i];
}
int k = m;
for (int i = n - 2;i >= 0;i--) {
while (m > k && Cross(stk[m - 1] - stk[m - 2], p[i] - stk[m - 2]) <= 0) m--;
stk[m++] = p[i];
}
if (n > 1) m--;
stk.resize(m);
return stk;
}
旋转卡壳求凸包的直径
intdiameter2(vector<Point> &points){
auto p = ConvexHell(points);
int n = p.size();
if (n == 1) return0;
elseif (n == 2) returnDist2(p[0], p[1]);
p.push_back(p[0]);
int ans = 0;
for (int u = 0, v = 1;u < n;u++) {
for (;;) {
int diff = Cross(p[u + 1] - p[u], p[v + 1] - p[v]);
if (diff <= 0) {
ans = max(ans, Dist2(p[u], p[v]));
if (diff == 0) ans = max(ans, Dist2(p[u], p[v + 1]));
break;
}
v = (v + 1) % n;
}
}
return ans;
}
图论
最大流、最小割
template<classT>
structMaxFlow {
struct_Edge {
int to;
T cap;
_Edge(int to, T cap) : to(to), cap(cap) {}
};
int n;
std::vector<_Edge> e;
std::vector<std::vector<int>> g;
std::vector<int> cur, h;
MaxFlow() {}
MaxFlow(int n) {
init(n);
}
voidinit(int n){
this->n = n;
e.clear();
g.assign(n, {});
cur.resize(n);
h.resize(n);
}
boolbfs(int s, int t){
h.assign(n, -1);
std::queue<int> que;
h[s] = 0;
que.push(s);
while (!que.empty()) {
constint u = que.front();
que.pop();
for (int i : g[u]) {
auto [v, c] = e[i];
if (c > 0 && h[v] == -1) {
h[v] = h[u] + 1;
if (v == t) {
returntrue;
}
que.push(v);
}
}
}
returnfalse;
}
T dfs(int u, int t, T f){
if (u == t) {
return f;
}
auto r = f;
for (int &i = cur[u]; i < int(g[u].size()); ++i) {
constint j = g[u][i];
auto [v, c] = e[j];
if (c > 0 && h[v] == h[u] + 1) {
auto a = dfs(v, t, std::min(r, c));
e[j].cap -= a;
e[j ^ 1].cap += a;
r -= a;
if (r == 0) {
return f;
}
}
}
return f - r;
}
voidaddEdge(int u, int v, T c){
g[u].push_back(e.size());
e.emplace_back(v, c);
g[v].push_back(e.size());
e.emplace_back(u, 0);
}
T flow(int s, int t){
T ans = 0;
while (bfs(s, t)) {
cur.assign(n, 0);
ans += dfs(s, t, std::numeric_limits<T>::max());
}
return ans;
}
std::vector<bool> minCut(){
std::vector<bool> c(n);
for (int i = 0; i < n; i++) {
c[i] = (h[i] != -1);
}
return c;
}
structEdge {
int from;
int to;
T cap;
T flow;
};
std::vector<Edge> edges(){
std::vector<Edge> a;
for (int i = 0; i < e.size(); i += 2) {
Edge x;
x.from = e[i + 1].to;
x.to = e[i].to;
x.cap = e[i].cap + e[i + 1].cap;
x.flow = e[i + 1].cap;
a.push_back(x);
}
return a;
}
};
最小费用最大流
template<classT>
structMaxFlow {
struct_Edge {
int to;
T cap;
_Edge(int to, T cap) : to(to), cap(cap) {}
};
int n;
std::vector<_Edge> e;
std::vector<std::vector<int>> g;
std::vector<int> cur, h;
MaxFlow() {}
MaxFlow(int n) {
init(n);
}
voidinit(int n){
this->n = n;
e.clear();
g.assign(n, {});
cur.resize(n);
h.resize(n);
}
boolbfs(int s, int t){
h.assign(n, -1);
std::queue<int> que;
h[s] = 0;
que.push(s);
while (!que.empty()) {
constint u = que.front();
que.pop();
for (int i : g[u]) {
auto [v, c] = e[i];
if (c > 0 && h[v] == -1) {
h[v] = h[u] + 1;
if (v == t) {
returntrue;
}
que.push(v);
}
}
}
returnfalse;
}
T dfs(int u, int t, T f){
if (u == t) {
return f;
}
auto r = f;
for (int &i = cur[u]; i < int(g[u].size()); ++i) {
constint j = g[u][i];
auto [v, c] = e[j];
if (c > 0 && h[v] == h[u] + 1) {
auto a = dfs(v, t, std::min(r, c));
e[j].cap -= a;
e[j ^ 1].cap += a;
r -= a;
if (r == 0) {
return f;
}
}
}
return f - r;
}
voidaddEdge(int u, int v, T c){
g[u].push_back(e.size());
e.emplace_back(v, c);
g[v].push_back(e.size());
e.emplace_back(u, 0);
}
T flow(int s, int t){
T ans = 0;
while (bfs(s, t)) {
cur.assign(n, 0);
ans += dfs(s, t, std::numeric_limits<T>::max());
}
return ans;
}
std::vector<bool> minCut(){
std::vector<bool> c(n);
for (int i = 0; i < n; i++) {
c[i] = (h[i] != -1);
}
return c;
}
structEdge {
int from;
int to;
T cap;
T flow;
};
std::vector<Edge> edges(){
std::vector<Edge> a;
for (int i = 0; i < e.size(); i += 2) {
Edge x;
x.from = e[i + 1].to;
x.to = e[i].to;
x.cap = e[i].cap + e[i + 1].cap;
x.flow = e[i + 1].cap;
a.push_back(x);
}
return a;
}
};
tarjan ecc 缩点,求桥
structedge
{
int v, ne;
} e[M];
int h[N], idx = 1;
int dfn[N], low[N], tot;
stack<int> stk;
int dcc[N], cnt;
int bri[M], d[N];
voidadd(int a, int b){
e[++idx].v = b;
e[idx].ne = h[a];
h[a] = idx;
}
voidtarjan(int x, int in_edg){
dfn[x] = low[x] = ++tot;
stk.push(x);
for (int i = h[x]; i; i = e[i].ne)
{
int y = e[i].v;
if (!dfn[y])
{
tarjan(y, i);
low[x] = min(low[x], low[y]);
if (low[y] > dfn[x])
bri[i] = bri[i ^ 1] = true;
}
elseif (i != (in_edg ^ 1))
low[x] = min(low[x], dfn[y]);
}
if (dfn[x] == low[x])
{
++cnt;
while (1)
{
int y = stk.top();
stk.pop();
dcc[y] = cnt;
if (y == x)
break;
}
}
}
tarjan vcc 缩点,求割点
constint MAXN = 1e5 + 10;
int n, m;
vector<int> edge[MAXN];
vector<int> vcc[MAXN];
vector<int> vcc_edge[MAXN];
vector<int> id(MAXN);
int dfn[MAXN], low[MAXN];
bool cut[MAXN];
int tot = 0,cnt = 0;
stack<int> stk;
voidtarjan(int u){
dfn[u] = low[u] = ++tot;
stk.emplace(u);
if (edge[u].empty()){
vcc[++cnt].emplace_back(u);
return ;
}
for (auto &it : edge[u]){
if (!dfn[it]){
tarjan(it);
low[u] = min(low[u],low[it]);
if (low[it] >= dfn[u]){
cut[u] = true;
}
cnt++;
int y;
do
{
y = stk.top();
vcc[cnt].emplace_back(y);
stk.pop();
} while (y == it);
vcc[cnt].emplace_back(u);
}
else{
low[u] = min(low[u],dfn[it]);
}
}
}
tarjan scc 缩点,求强连通分量
vector<int> edge[N];
int dfn[N], low[N], top = 0, stk[N];
bool instk[N];
int timer = 0, scc_cnt = 0;
//无论对于一个有向图还是无向图来说,缩点后的结果一定是一个森林voidtarjan(int u){
low[u] = dfn[u] = ++timer;
stk[++top] = u;
instk[u] = true;
for (auto v : edge[u])
{
if (!dfn[v])
{
tarjan(v);
low[u] = min(low[u], low[v]);
}
elseif (instk[v])
{
low[u] = min(low[u], low[v]);
}
}
if (dfn[u] == low[u])
{
scc_cnt ++;
scc[u] = scc_cnt;
instk[u] = false;
while (stk[top] != u) {
scc[stk[top]] = scc_cnt;
instk[stk[top--]] = false;
}
top --;
}
}
数论
线性筛
for (int i = 2; i <= n; i++) {
if (!isPrime[i]){
prime[++cnt] = i;
}
for (int j = 1; j <= cnt && i * prime[j] <= n; j++){
isPrime[i * prime[j]] = 1;
if (i % prime[j] == 0){
break;
}
}
}
扩展中国剩余定理
template<class T>
T exgcd(T a, T b, T &x, T &y){
if (!b) {
x = 1, y = 0;
return a;
}
T d = exgcd(b, a % b, y, x);
y -= a / b * x;
return d;
}
template<class T>
T mul(T a, T b, T mod){
a = (a % mod + mod) % mod;
b = (b % mod + mod) % mod;
T ans = 0;
while (b != 0) {
if ((b & 1) != 0) {
ans = (ans + a) % mod;
}
a = (a + a) % mod;
b >>= 1;
}
return ans;
}
template<class T>
T excrt(vector<T> &m, vector<T> &r){
T tail = 0, lcm = 1, tmp, b, c, x0, x, y, d;
for (int i = 0;i < m.size();i++) {
b = m[i]; c = ((r[i] - tail) % b + b) % b;
d = exgcd(lcm, b, x, y);
if (c % d != 0) return-1;
x0 = mul(x, c / d, b / d);
tmp = lcm * (b / d);
tail = (tail + mul(x0, lcm, tmp)) % tmp;
lcm = tmp;
}
return tail;
}
exgcd
template <classT> T sign(const T &a){
return a == 0 ? 0 : (a < 0 ? -1 : 1);
}
template <classT> T ceil(const T &a, const T &b){
T A = abs(a), B = abs(b);
assert(b != 0);
returnsign(a) * sign(b) > 0 ? (A + B - 1) / B : -A / B;
}
template<class T>
T exgcd(T a, T b, T &x, T &y){
if (!b) {
x = 1, y = 0;
return a;
}
T d = exgcd(b, a % b, y, x);
y -= a / b * x;
return d;
}
template<class T>
voidexgcd(T a, T b, T c){
T x, y, d = exgcd(a, b, x, y);
if (c % d != 0) {
cout << "Impossible" << endl;
return ;
}
x *= c / d, y *= c / d;
T p = b / d, q = a / d, k;
if (x < 0) {
k = ceil(1 - x, p);
x += p * k;
y -= q * k;
}
elseif (x >= 0) { //将x提高到最小正整数
k = (x - 1) / p;
x -= p * k; //将x降低到最小正整数
y += q * k;
}
if (y > 0) { //有正整数解
cout << (y - 1) / q + 1 << endl; //将y减到1的方案数即为解的个数
cout << x << endl; //当前的x即为最小正整数x
cout << (y - 1) % q + 1 << endl; //将y取到最小正整数
cout << x + (y - 1) / q * p << endl; //将x提升到最大
cout << y << endl; //特解即为y最大值
} else { //无整数解
cout << x << endl; //当前的x即为最小的正整数x
cout << y + q * ceil(1 - y, q) << endl; //将y提高到正整数
}
}
exlucas
template<class T>
T qpow(T a, T b, T mod){
T ans = 1;
for (;b;b >>= 1, a = a * a % mod)
if (b & 1) ans = ans * a % mod;
return ans;
}
template<class T>
T exgcd(T a, T b, T &x, T &y){
if (!b) {
x = 1, y = 0;
return a;
}
T d = exgcd(b, a % b, y, x);
y -= a / b * x;
return d;
}
template<class T>
T mul(T a, T b, T mod){
a = (a % mod + mod) % mod;
b = (b % mod + mod) % mod;
T ans = 0;
while (b != 0) {
if ((b & 1) != 0) {
ans = (ans + a) % mod;
}
a = (a + a) % mod;
b >>= 1;
}
return ans;
}
template<class T>
T excrt(vector<T> &m, vector<T> &r){
T tail = 0, lcm = 1, tmp, b, c, x0, x, y, d;
for (int i = 0;i < m.size();i++) {
b = m[i]; c = ((r[i] - tail) % b + b) % b;
d = exgcd(lcm, b, x, y);
if (c % d != 0) return-1;
x0 = mul(x, c / d, b / d);
tmp = lcm * (b / d);
tail = (tail + mul(x0, lcm, tmp)) % tmp;
lcm = tmp;
}
return tail;
}
constint MAXN = 4e4 + 10;
i64 fact[MAXN];
template<class T>
T inv(T a, T mod){
returnqpow(a, mod - 2, mod);
}
template<class T>
T C(T n, T m, T mod){
if (n < m) return0;
return fact[n] * inv(fact[m], mod) % mod * inv(fact[n - m], mod) % mod;
}
template<class T>
T lucas(T n, T m, T mod){
if (n < m) return0;
if (!n) return1;
returnlucas(n / mod, m / mod, mod) * C(n % mod, m % mod, mod) % mod;
}
高斯消元
constdouble eps = 1e-7;
inlineintdcmp(double a, double b){
if (fabs(a - b) < eps) return0;
return a > b ? 1 : -1;
}
//最普通的高斯消元voidgauss(vector<vector<double>> &matrix){
int n = matrix.size();
for (int i = 0;i < n;i++) {
int r = i;
for (int j = i + 1;j < n;j ++)
if (dcmp(fabs(matrix[r][i]), fabs(matrix[j][i])) == -1) r = j;
if (dcmp(matrix[r][i], 0.0) == 0) {
printf("No Solution\n");
return ;
}
if (i != r) swap(matrix[i], matrix[r]);
double div = matrix[i][i];
for (int j = i;j <= n;j++) matrix[i][j] /= div;
for (int j = i + 1;j < n;j++) {
div = matrix[j][i];
for (int k = i;k <= n;k++) matrix[j][k] -= matrix[i][k] * div;
}
}
vector<double> ans(n);
ans[n - 1] = matrix[n - 1][n];
for (int i = n - 2;i >= 0;i--) {
ans[i] = matrix[i][n];
for (int j = i + 1;j < n;j++) ans[i] -= matrix[i][j] * ans[j];
}
for (int i = 0;i < n;i++) printf("%.2lf\n", ans[i]);
}
//区分无解,多解和唯一解voidgauss2(vector<vector<double>> &matrix){
int n = matrix.size();
for (int i = 0;i < n;i++) {
int mx = i;
for (int j = 0;j < n;j++) {
if (j < i && fabs(matrix[j][j]) >= eps) continue;
if (dcmp(fabs(matrix[j][i]), fabs(matrix[mx][i])) == 1) mx = j;
}
if (mx != i) swap(matrix[mx], matrix[i]);
if (fabs(matrix[i][i]) >= eps) {
double div = matrix[i][i];
for (int j = i;j <= n;j++) matrix[i][j] /= div;
for (int j = 0;j < n;j++) {
if (i == j) continue;
div = matrix[j][i] / matrix[i][i];
for (int k = i;k <= n;k++) matrix[j][k] -= div * matrix[i][k];
}
}
}
bool flag = true;
for (int i = 0;i < n;i++) {
if ((fabs(matrix[i][i]) < eps) && (fabs(matrix[i][n]) >= eps)) {
printf("-1\n");
return ;
}
if (fabs(matrix[i][i]) < eps) flag = false;
}
if (!flag) printf("0\n");
else {
for (int i = 0;i < n;i++) printf("x%d=%.2lf\n", i + 1, matrix[i][n]);
}
}
// 异或方程组voidGauss3(vector<vector<int>> &matrix){
int n = matrix.size();
for (int i = 0;i < n;i++) {
int is = i;
for (int j = 0;j < n;j++) {
if (j < i && matrix[j][j] == 1) continue;
if (matrix[j][i] == 1) {
swap(matrix[i], matrix[j]);
break;
}
}
if (matrix[i][i] != 1) continue;
for (int j = 0;j < n;j++) {
if (i == j) continue;
if (matrix[j][i] == 1) {
for (int k = i;k <= n;k++) matrix[j][k] ^= matrix[i][k];
}
}
}
}
//同余方程组(要求mod相同)constint mod = 1e9 + 7;
voidGauss4(vector<vector<int>> &matrix){
int n = matrix.size(), m = matrix[0].size();
for (int i = 1;i <= n;i++) {
for (int j = 1;j <= n;j++) {
if (j < i && matrix[j][j] != 0) continue;
if (matrix[j][i] != 0) {
swap(matrix[j], matrix[i]);
break;
}
}
if (matrix[i][i] == 0) break;
for (int j = 1;j <= n;j++) {
if (i == j || matrix[j][i] == 0) continue;
int gcdNum = __gcd(matrix[i][i], matrix[j][i]);
int a = matrix[i][i] / gcdNum, b = matrix[j][i] / gcdNum;
if (j < i && matrix[j][j] != 0) {
for (int k = j;k < i;k++) matrix[j][k] = (matrix[j][k] * a) % mod;
}
for (int k = i;k <= n + 1;k++)
matrix[j][k] = (matrix[j][k] * a % mod - matrix[i][k] * b % mod + mod) % mod;
}
}
}
欧拉函数
constexprint N = 1E7;
constexprint P = 1000003;
bool isprime[N + 1];
int phi[N + 1];
std::vector<int> primes;
std::fill(isprime + 2, isprime + N + 1, true);
phi[1] = 1;
for (int i = 2; i <= N; i++) {
if (isprime[i]) {
primes.push_back(i);
phi[i] = i - 1;
}
for (auto p : primes) {
if (i * p > N) {
break;
}
isprime[i * p] = false;
if (i % p == 0) {
phi[i * p] = phi[i] * p;
break;
}
phi[i * p] = phi[i] * (p - 1);
}
}
// 求单个数的欧拉函数intphi(int n){
int res = n;
for (int i = 2; i * i <= n; i++) {
if (n % i == 0) {
while (n % i == 0) {
n /= i;
}
res = res / i * (i - 1);
}
}
if (n > 1) {
res = res / n * (n - 1);
}
return res;
}
线性基
uint64_t p[52];
voidinsert(uint64_t x){
for (int i = 51; ~i; i--) {
if (!(x >> i)) continue;
if (!p[i]) {
p[i] = x;
break;
}
x ^= p[i];
}
}
// 求异或和最大uint64_t ans = 0;
for (int i = 51; ~i; i--)
ans = max(ans, ans ^ p[i]);
cout << ans << endl;
杂项
离散化
for (int i = 1; i <= n; i++)
lsh[i] = a[i] = read();
sort(lsh + 1, lsh + n + 1);
int m = unique(lsh + 1, lsh + n + 1) - lsh - 1;
for (int i = 1; i <= n; i++)
a[i] = lower_bound(lsh + 1, lsh + m + 1, a[i]) - lsh;
公式
C(n,m)%2 = (n&m)==m
约瑟夫问题:
F(n,m) = 有 n 个人 (0,1,2,..,n−1),每次杀掉编号为(x + m) % n的人,最终的幸存者。
F(n,m) = (F(n − 1, m) + m) % n
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!