ACM板子堆
数据结构
玄学数据结构——珂朵莉树
struct Node {
int l,r;// [l,r]
mutable int v; // 需要维护的信息
Node(int LL ,int rr = -1,int vv = 0):l(LL), r(rr),v(vv){}
bool operator<(const Node &o) const {return l < o.l;}
};
set<Node> s;
#define IT set<Node>::iterator
IT split(int p) { // split [l,r] into [l,p-1] and [p,r]
IT it = s.lower_bound(Node(p));
if(it != s.end() && it->l == p) return it;
it --;
int L = it->l, R = it->r, V = it->v;
s.erase(it);
s.insert(Node(L,p - 1,V));
return s.insert(Node(p,R,V)).first;
}
void assign(int l,int r,int val) {// 区间覆盖
IT end = split(r + 1),beg = split(l);// 一定要先split右边
s.erase(beg,end);
s.insert(Node(l,r,val));
}
int query(int l,int r) {
IT end = split(r + 1),beg = split(l);// 一定要先split右边
int ans = 0;
for(auto it = beg;it != end;it ++) {
// do something
}
return ans;
}
并查集
struct DSU {
vector<int> fa, sz;
int n;
DSU(int _n) : n(_n), fa(_n), sz(_n, 1) {
iota(fa.begin(), fa.end(), 0);
}
bool merge(int x, int y) {
x = find(x); y = find(y);
if (x == y) return false;
if(sz[x] > sz[y]) {
swap(x,y);
}
fa[x] = y;
sz[y] += sz[x];
return true;
}
int find(int x) {
return fa[x] == x ? x : (fa[x] = find(fa[x]));
}
bool same(int x, int y) {
return find(x) == find(y);
}
int getSz(int x) {
return sz[find(x)];
}
};
单调栈
单调栈求 max 的管辖区间
void getLR(vector<int> &a,vector<int> &L,vector<int> &R) {
int n = a.size() - 1;
L.resize(n + 1,1);
R.resize(n + 1,n);
stack<int> stk;// dec 5 4 3 2 4
rep(i,1,n) {
while(stk.size() && a[stk.top()] <= a[i]) stk.pop();
if(stk.size()) L[i] = stk.top() + 1;
stk.push(i);
}
while(stk.size()) stk.pop();
per(i,n,1) {
while(stk.size() && a[stk.top()] <= a[i]) stk.pop();
if(stk.size()) R[i] = stk.top() - 1;
stk.push(i);
}
}
线段树
区间加,区间查询
template<class Info, class Tag>
struct LazySegTree {
int L = 0, R = 0;
vector<Info> info;
vector<Tag> tag;
int ls(int p) {return p << 1;}
int rs(int p) {return p << 1 | 1;}
void pushup(int p) {
info[p] = info[ls(p)] + info[rs(p)];
}
void build(int p, int l, int r, vector<Info> &a) {
if (r == l) {
info[p] = a[l];
return;
}
int m = l + r >> 1;
build(ls(p), l, m, a);
build(rs(p), m + 1, r, a);
pushup(p);
}
void init(int _L, int _R, vector<Info> &A) {
int n = A.size();
L = _L, R = _R;
info = vector<Info>(n << 2);
tag = vector<Tag>(n << 2);
build(1, L, R, A);
}
void apply(int p, const Tag &t) {
info[p].apply(t);
tag[p].apply(t);
}
void pushdown(int p) {
apply(ls(p), tag[p]);
apply(rs(p), tag[p]);
tag[p] = Tag();
}
void modify(int p, int l, int r, int ql, int qr, const Tag &v) {
if (l > qr or r < ql) {
return;
}
if (ql <= l and r <= qr) {
apply(p, v);
return;
}
pushdown(p);
int m = l + r >> 1;
modify(ls(p), l, m, ql, qr, v);
modify(rs(p), m + 1, r, ql, qr, v);
pushup(p);
return;
}
Info query(int p, int l, int r, int ql, int qr) {
if (l > qr or r < ql) {
return Info();
}
if (ql <= l and r <= qr) {
return info[p];
}
pushdown(p);
int m = l + r >> 1;
return query(ls(p), l, m, ql, qr) + query(rs(p), m + 1, r, ql, qr);
}
Info query(int ql, int qr) {
return query(1, L, R, ql, qr);
}
void modify(int ql, int qr, const Tag &v) {
modify(1, L, R, ql, qr, v);
}
};
/*
仿jls的LazyTagSegmentTree 第一版
只需实现Tag和Info的无参构造(如果没有其他构造则可以不写)
二者的Tag注入函数apply, 当需要单点更新时调用(pushdown与modify).
将所有更新信息都抽象为一个Tag的注入,考虑这个tag记录的信息对info和tag的影响即可.
重载的+号算符.
初始化函数init, 用于将原始信息转为info.
*/
struct Tag {
ll add = 0;
Tag () {}
Tag(ll _add) : add(_add) {}
void apply(const Tag &t) {
add += t.add;
}
};
struct Info {
ll s = 0;
int l = 0, r = 0;
Info () {}
Info (int _l, int _r, ll _s) : l(_l), r(_r), s(_s) {}
void apply(const Tag &t) {
s += t.add * (r - l + 1);
}
};
Info operator+ (const Info &a, const Info &b) {
Info ans;
ans.l = a.l;
ans.r = b.r;
ans.s = a.s + b.s;
return ans;
}
void init(LazySegTree<Info, Tag> &t, vector<int> &a) {
int n = a.size();
vector<Info> info(n);
for (int i = 0; i < n; i++) {
info[i] = Info(i, i, a[i]);
}
t.init(0, n - 1, info);
}
区间max,区间修改
struct Tag {
long long mx = 0;
void apply(const Tag& t) {
mx = max(mx, t.mx);
}
};
struct Info {
long long mx = 0;
void apply(const Tag& t) {
mx = max(mx, t.mx);
}
};
Info operator+ (const Info &a, const Info &b) {
return {max(a.mx, b.mx)};
}
ST 表
for(int i = 1;i <= N;i ++) f[i][0] = a[i];
for(int j = 1;j <= 20;j ++)
for(int i = 1;i + (1ll << j) - 1 <= N;i ++)
f[i][j] = max(f[i][j - 1], f[i + (1ll << j - 1)][j - 1]);
auto getmax = [&](int l, int r) {
int t = __lg(r - l + 1);
return max(f[l][t], f[r - (1ll << t) + 1][t]); // 注意和预处理时的区别
};
封装好的:
template <typename T>
struct ST
{
ST(vector<T> a, int n) { // cope with in [0,n]
siz = n;
maxv.resize(n + 1), minv.resize(n + 1);
maxid.resize(n + 1), minid.resize(n + 1);
int t = __lg(n) + 1;
for (int i = 0; i <= n; i++) {
maxv[i].resize(t), minv[i].resize(t);
maxid[i].resize(t), minid[i].resize(t);
}
for (int i = 0; i <= n; i++) {
maxv[i][0] = minv[i][0] = a[i];
maxid[i][0] = minid[i][0] = i;
}
for (int j = 1; j < t; j++) {
for (int i = 0; i <= n - (1 << j) + 1; i++) {
T lv, rv;
maxv[i][j] = max(lv = maxv[i][j - 1], rv = maxv[i + (1 << (j - 1))][j - 1]);
maxid[i][j] = lv > rv ? maxid[i][j - 1] : maxid[i + (1 << j - 1)][j - 1];
minv[i][j] = min(lv = minv[i][j - 1], rv = minv[i + (1 << (j - 1))][j - 1]);
minid[i][j] = lv < rv ? minid[i][j - 1] : minid[i + (1 << j - 1)][j - 1];
}
}
}
T getMax(int l, int r) {
int k = __lg(r - l + 1);
return max(maxv[l][k], maxv[r - (1 << k) + 1][k]);
}
T getMin(int l, int r) {
int k = __lg(r - l + 1);
return min(minv[l][k], minv[r - (1 << k) + 1][k]);
}
T getMinId(int l, int r) {
int k = __lg(r - l + 1);
if (minv[l][k] < minv[r - (1 << k) + 1][k]) return minid[l][k];
return minid[r - (1 << k) + 1][k];
}
T getMaxId(int l, int r) {
int k = __lg(r - l + 1);
if (maxv[l][k] > maxv[r - (1 << k) + 1][k]) return maxid[l][k];
return maxid[r - (1 << k) + 1][k];
}
private:
int siz = 0;
vector<vector<T>> maxv, minv;
vector<vector<T>> maxid, minid;
};
python version
class ST:
def __init__(self, a):
n = len(a)
m = len(a).bit_length() + 1
mnArr = [[float('inf')] * n for _ in range(m)]
mxArr = [[-float('inf')] * n for _ in range(m)]
for i in range(n):
mnArr[0][i] = mxArr[0][i] = a[i]
for i in range(1, m):
for j in range(n - (1 << i - 1)):
mxArr[i][j] = max(mxArr[i - 1][j], mxArr[i - 1][j + (1 << i - 1)])
mnArr[i][j] = min(mnArr[i - 1][j], mnArr[i - 1][j + (1 << i - 1)])
self.n = n
self.m = m
self.mnArr = mnArr
self.mxArr = mxArr
def queryMax(self, l, r):
t = (r - l + 1).bit_length() - 1
return max(self.mxArr[t][l], self.mxArr[t][r - (1 << t) + 1])
def queryMin(self, l, r):
t = (r - l + 1).bit_length() - 1
return min(self.mnArr[t][l], self.mnArr[t][r - (1 << t) + 1])
并查集
int fa[MAXN];
void init(int n) {
for(int i = 0;i <= n;i ++) fa[i] = i;
}
int root(int x) {
if(x == fa[x]) return x;
return fa[x] = root(fa[x]);
}
void unite(int x, int y) {
fa[root(x)] = root(y);// 将 y 并入 x
}
bool same(int x,int y) {
return root(x) == root(y);
}
树状数组
朴素BIT
struct BIT {
int n;
vector<int> t;
BIT(int _n) {
t.resize(_n + 1,0);
n = _n;
}
void init(int _n) {
t.resize(_n + 1,0);
n = _n;
}
int lowbit(int x) {return x & (-x);}
int query(int p) {
int ans = 0;
for(;p > 0;p -= lowbit(p)) ans += t[p];
return ans;
}
void add(int p, int x) {
for(;p <= n;p += lowbit(p)) t[p] += x;
}
int query(int l,int r) {return query(r) - query(l - 1);}
};
RMQ树状数组
时间复杂度2个log
struct RMQBIT {
/*
a:需要复制原数组
tr:树状数组
*/
vector<int> tr;
vector<int> a;
int n;
RMQBIT (vector<int> vec,int _n):a(vec),n(_n) {
tr.resize(n + 1,0);
for(int i = 1;i <= n;i += 1) upd(i,vec[i]);
}
int lowbit(int x) {return x&-x;}
void upd(int p,int val) {
a[p] = val;// 需要先对原数组做单点修改
while(p <= n) {
tr[p] = a[p];
for(int i = 1;i < lowbit(p);i <<= 1)
tr[p] = max(tr[p], tr[p - i]);
p += lowbit(p);
}
}
int query(int l,int r) {
int ans = 0;
// 递归切割 [query(l,r-lb+1),tr[r]] 或者 [query(l,r-1),r]
while(l <= r) {
ans = max(ans, a[r]);
r -= 1;// 总先进行一个小的切割,避免边界情况
// [l,r] 包裹 [r - lowbit(r) + 1,r]
while(r - lowbit(r) >= l) {
ans = max(ans, tr[r]);
r -= lowbit(r);
}
}
return ans;
}
};
朴素根号分块
// 假定对数组 a[] 进行分块,长度N,下标从1开始
// 分块初始化
int L[N + 1], R[N + 1];// 左右端点
int blc = sqrt(N);
for(int i = 1;i <= blc;i ++) {
L[i] = (i - 1) * sqrt(N) + 1;
R[i] = i * sqrt(N);
}
if(R[blc] <= N) {// 末尾长度不足 blc 的分一块
blc ++;
L[blc] = R[blc - 1] + 1;
R[blc] = N;
}
// 预处理
int belong[N + 1];// 第i个元素属于哪个块
for(int i = 1;i <= blc;i ++) {
for(int j = L[i];j <= R[i];j ++) {
belong[j] = i;
// do something
}
}
// ask
int ask(int r) {
int ans = 0;
if(R[1] > r) {
// 暴力
return ans;
}
int start = -1;
for(int i = 1;i <= blc;i ++) {
if(R[i] <= r) {
// 合并
}else {
start = R[i] + 1;
break;
}
}
if(start != -1) {
// 暴力处理最后区间
}
return ans;
}
树的直径
auto getD = [&](int s) {
queue<int> q;
vector<int> dis(n + 1,-1);
dis[s] = 0;
q.push(s);
int ans = s,mx = 0;
while(q.size()) {
int u = q.front(); q.pop();
for(int v : adj[u]) if(dis[v] == -1) {
dis[v] = dis[u] + 1;
q.push(v);
if(mx < dis[v]) {
mx = dis[v];
ans = v;
}
}
}
return ans;
};
int V = getD(1), W = getD(V);
树剖LCA
vector<int> dep(n + 1),par(n + 1),sz(n + 1),son(n + 1);
function<void(int,int)> dfs1 = [&](int u,int fa) {
dep[u] = dep[fa] + 1;
par[u] = fa;
sz[u] += 1;
for(auto v : adj[u]) if(v != fa) {
dfs1(v,u);
if(sz[v] > sz[son[u]]) son[u] = v;
sz[u] += sz[v];
}
};
dfs1(rt,0);
vector<int> top(n + 1);
function<void(int,int)> dfs2 = [&](int u,int t) {
top[u] = t;
if(son[u]) dfs2(son[u],t);
for(auto v : adj[u]) if(v != par[u] and v != son[u]) dfs2(v,v);
};
dfs2(rt,rt);
auto lca = [&](int x,int y) {
while(top[x] != top[y]) {
if(dep[top[x]] > dep[top[y]]) x = par[top[x]];
else y = par[top[y]];
}
return dep[x] > dep[y] ? y : x;
};
倍增LCA
int dep[MAXN],p[MAXN][21];
void dfs(int u,int fa) {
dep[u] = dep[fa] + 1;
p[u][0] = fa;
for(int i = 1;(1 << i) <= dep[u];i ++) {
p[u][i] = p[p[u][i - 1]][i - 1];
}
for(auto v : adj[u]) if(v != fa) dfs(v,u);
}
int lca(int x,int y) {
if(dep[x] < dep[y]) swap(x,y);
for(int i = 20;i >= 0;i --) {
if(dep[p[x][i]] >= dep[y])
x = p[x][i];
}
if(x == y) return x;
for(int i = 20;i >= 0;i --) {
if(p[x][i] != p[y][i])
x = p[x][i], y = p[y][i];
}
return p[x][0];
}
数学
高斯消元
void guass(double a[][N], int n, int m) {// 矩阵,行数,列数,from 0
for(int c = 0;c < min(n, m);c ++) {
int r = c;
for(int i = r + 1;i < n;i ++) if(a[i][c] > a[r][c])
r = i;
swap(a[c], a[r]);
if(abs(a[r][c]) < 1e-9) {
//cout << "No Solution\n";
return;
}
for(int i = 0;i < n;i ++) if(i != c) {
double t = a[i][c] / a[c][c];
for(int j = c;j < m;j ++) {
a[i][j] -= t * a[c][j];
}
}
// rep(o,0,n-1)rep(p,0,m-1)cout<<a[o][p]<<" \n"[p==m-1];cout<<'\n';
}
//for(int i = 0;i < n;i ++)
// cout << fixed << setprecision(2) << a[i][m - 1] / a[i][i] << endl;
}
行列式求值
int n;
int a[N][N];
int ksm(int a,int b) {
int ans = 1;
a %= mod;
while(b) {
if(b & 1) ans = ans * a % mod;
a = a * a % mod;
b >>= 1;
}
return ans;
}
/*
行列式求值
mod是一个质数
需要快速幂求逆元
*/
int guass(int a[][N], int n, int m) {
int cnt = 0, ans = 1;
for(int c = 0;c < min(n, m);c ++) {
int r = c;
for(int i = r + 1;i < n;i ++) if(a[i][c] > a[r][c])
r = i;
cnt += r != c;
swap(a[c], a[r]);
if(a[r][c] == 0) {
return 0;
}
ans = ans * a[c][c] % mod;
for(int i = 0;i < n;i ++) if(i != c) {
int t = a[i][c] * ksm(a[c][c], mod - 2) % mod;
for(int j = c;j < m;j ++) {
a[i][j] -= t * a[c][j] % mod;
a[i][j] = (a[i][j] % mod + mod) % mod;
}
}
}
if(cnt & 1) ans = mod - ans;
return ans;
}
线性基
struct LinearBase {
const int MAXL = 64;
vector<int> b;
int n;
void build(vector<int> &a) {// a start from 1 ,cope with [1,n]
b.resize(MAXL);
n = (int)a.size() - 1;
for(int i = 1;i <= n;i += 1) insert(a[i]);
}
bool insert(int x) {// 返回是否插入成功
for(int i = MAXL - 1;i >= 0;i -= 1) {
if(x >> i & 1) {
if(!b[i]) {
b[i] = x;
// 对b[i],[0,i) 位有1试着用b[j]消去 注意遍历顺序
for(int j = i - 1;j >= 0;j -= 1) if(b[i] >> j & 1)
b[i] ^= b[j];
// 对b[j],(i,MAX] 位有1试着用b[i]消去
for(int j = i + 1;j < MAXL;j += 1) if(b[j] >> i & 1)
b[j] ^= b[i];
break;
}
x ^= b[i];
}
}
return x > 0;
}
int getMax() {
int ans = 0;
for(int i = MAXL - 1;i >= 0;i -= 1)
ans = max(ans, ans ^ b[i]);
return ans;
}
int getKthMin(int k) {
int cnt = 0;
for(int i = 0;i < MAXL;i += 1) cnt += b[i] != 0;
k -= cnt < n;// 特判0
if(k > (1ll << cnt) - 1) return -1;// k 太大
int ans = 0;
for(int i = 0,j = 0;i < MAXL;i += 1) if(b[i]) {
if(k >> j & 1) ans ^= b[i];
j += 1;
}
return ans;
}
}lb;
质数
namespace prime {
vector<int> primes;
vector<int> init(int n) {
vector<bool> iscom(n + 1);
for (int i = 2; i < n; i++) {
if (!iscom[i]) {
primes.emplace_back(i);
}
for (int p : primes) {
if (p * i >= n) break;
iscom[p * i] = true;
if (i % p == 0) break;
}
}
return primes;
}
vector<pair<int, int>> factorize(long long x) {
vector<pair<int, int>> factors;
for (int &p : primes) {
if (x % p == 0) {
int cnt = 0;
while (x % p == 0) {
++cnt;
x /= p;
}
factors.emplace_back(p, cnt);
}
}
if (x != 1) factors.emplace_back(x, 1);
return factors;
}
}
线性逆元&组合数计算
int fac[MAXN],invfac[MAXN],inv[MAXN];
void init() {
inv[1] = invfac[1] = invfac[0] = fac[1] = fac[0] = 1;
for(int i = 2;i < MAXN;i ++) {
inv[i] = (mod - mod / i) * inv[mod % i] % mod;
fac[i] = fac[i - 1] * i % mod;
invfac[i] = invfac[i - 1] * inv[i] % mod;
}
}
int C(int n,int m) {
return fac[n] * invfac[m] % mod * invfac[n - m] % mod;
}
矩阵类
template <class T>
struct Matrix { // 矩阵类int n, m; // 0 ~ n-1 vector<vector<T> > a;
int n,m;
const double eps = 1e-7;
vector<vector<T>> a;
Matrix(const int row = 1, const int col = 1) {
n = row, m = col;
a = vector<vector<T>>(n, vector<T>(m, {0}));
}
Matrix(const Matrix &p) { n = p.n, m = p.m, a = p.a; }
Matrix<T> &operator=(const Matrix<T> &p) {
n = p.n, m = p.m, a = p.a;
return *this;
}
Matrix<T> operator+(const Matrix<T> &p) const {
Matrix<T> ans(n, m);
for (int i = 0; i < n; ++i)
for (int j = 0; j < m; ++j)
ans.a[i][j] = a[i][j] + p.a[i][j];
return ans;
}
Matrix<T> operator-(const Matrix<T> &p) const
{
Matrix<T> ans(n, m);
for (int i = 0; i < n; ++i)
for (int j = 0; j < m; ++j)
ans.a[i][j] = a[i][j] - p.a[i][j];
return ans;
}
Matrix<T> operator*(const Matrix<T> &p) const {
Matrix<T> ans(n, p.m);
for (int i = 0; i < n; ++i)
for (int j = 0; j < p.m; ++j)
for (int k = 0; k < m; ++k)
ans.a[i][j] = ans.a[i][j] + a[i][k] * p.a[k][j];
return ans;
}
Matrix<T> operator^(ll p) const {
Matrix<T> ans(n, n), b(*this);
for (int i = 0; i < n; ++i)
ans.a[i][i] = 1;
while (p) {
if (p & 1)
ans = ans * b;
b = b * b, p >>= 1;
}
return ans;
}
Matrix<T> GetInv() const {
Matrix<T> b(*this);
for (int i = 0; i < n; ++i)
for (int j = 0; j < n; ++j)
b.a[i].pb((j == i) ? T(1) : T(0));
for (int i = 0, k = 0; i < n; ++i, k = i) {
for (int j = i + 1; j < n; ++j)
if (fabs(b.a[j][i]) > fabs(b.a[k][i]))
k = j;
if (fabs(b.a[k][i]) < eps) {
b.n = -1;
return b;
}
swap(b.a[i], b.a[k]);
for (int j = i + 1; j < (n << 1); ++j)
b.a[i][j] = b.a[i][j] / b.a[i][i];
for (int j = 0; j < n; ++j)
if (j != i && fabs(b.a[j][i]) > eps)
for (k = i + 1; k < (n << 1); ++k)
b.a[j][k] = b.a[j][k] - b.a[i][k] * b.a[j][i];
}
for (int i = 0; i < n; ++i) {
for (int j = 0, k = n; j < n; ++j, ++k)
b.a[i][j] = b.a[i][k];
for (int j = 0; j < n; ++j)
b.a[i].pop_back();
}
return b;
}
T GetDet() const
{ // 0 ~ n - 1
vector<vector<T>> b(this->a);
T det = 1;
for (int i = 0, k = 0; i < n; ++i) {
for (int j = i + 1; j < n; ++j)
if (fabs(b[j][i]) > fabs(b[k][i]))
k = j;
if (fabs(b[k][i]) < eps) {
det = 0;
break;
}
swap(b[i], b[k]);
if (i != k)
det = -det;
det = det * b[i][i];
for (int j = i + 1; j < n; ++j)
b[i][j] = b[i][j] / b[i][i];
for (int j = 0; j < n; ++j)
if (j != i && fabs(b[j][i]) > eps)
for (k = i + 1; k < n; ++k)
b[j][k] = b[j][k] - b[i][k] * b[j][i];
}
return det;
}
vector<vector<T>> Gauss() const {
vector<vector<T>> ans(n, vector<T>(m - n, {0}));
Matrix<T> b(*this);
for (int i = 0, k = 0; i < n; ++i, k = i){
for (int j = i + 1; j < n; ++j)
if (fabs(b.a[j][i]) > fabs(b.a[k][i]))
k = j;
if (fabs(b.a[k][i]) < eps){
ans.resize(0);
break;
}
swap(b.a[i], b.a[k]);
for (int j = i + 1; j < m; ++j)
b.a[i][j] = b.a[i][j] / b.a[i][i];
for (int j = 0; j < n; ++j)
if (j != i && fabs(b.a[j][i]) > eps)
for (k = i + 1; k < m; ++k)
b.a[j][k] = b.a[j][k] - b.a[i][k] * b.a[j][i];
}
for (int i = 0; i < n; ++i){
for (int j = n; j < m; ++j)
ans[i][j - n] = b.a[i][j];
}
return ans;
}
};
扩展欧几里得
int exgcd(int a, int b, int &x, int &y) {
if (!b) {
x = 1, y = 0;
return a;
}
int d = exgcd(b, a % b, y, x);
y -= a / b * x;
return d;
}
非递归写法
tuple<int, int, int> exgcd(int a, int b) {
int r1, r0, s1, s0, t1, t0;
r0 = a, r1 = b;
s0 = 1, s1 = 0;
t0 = 0, t1 = 1;
if (!b) {
return make_tuple(r0, s0, t0);
}
while (r1) {
int q = r0 / r1;
int nr = r0 - r1 * q;
r0 = r1, r1 = nr;
int ns = s0 - s1 * q;
s0 = s1, s1 = ns;
int nt = t0 - t1 * q;
t0 = t1, t1 = nt;
}
return make_tuple(r0, s0, t0);
}
字符串
KMP
auto getNxt = [&](string &s) {
int n = s.size();
s = '$' + s;// from 1
vector<int> nxt(n + 1);
for(int i = 2,j = 0;i <= n;i += 1) {
while(j and s[i] != s[j + 1])
j = nxt[j];
nxt[i] = (j += s[i] == s[j + 1]);
}
return nxt;
};
Trie
01trie
namespace trie {
/*
N: 字符串最大长度*数量
S: 字符集大小
tot: 当前点个数
son: 当前点,走某字符边的儿子节点标号
cnt: 节点i代表的公共前缀数量
root=1,将0空出,代表null
*/
const int N = 1e5 * 31 + 5;
const int S = 2;
int tot = 1;
int son[N][S];
int cnt[N];
void insert(int x, int c) {
int p = 1;
for (int bit = 30; bit >= 0; bit--) {
int b = x >> bit & 1;
if (!son[p][b]) son[p][b] = ++tot;
p = son[p][b];
cnt[p] += c;
}
}
int find(int x) {
int p = 1;
for (int bit = 30; bit >= 0; bit--) {
int bx = x >> bit & 1;
p = son[p][bx];
}
return cnt[p];
}
void init() {
for (int i = 0;i <= tot;i ++) {
for (int j = 0;j < S;j ++) {
son[i][j] = cnt[i] = 0;
}
}
tot = 0;
}
}
更新一份非封装可以求xormax和xormin的
const int LEN = 2e5 + 5, LG = 31;
int son[LEN * LG][2], cnt[LEN * LG], tot = 1;
void insert(int num) {
int p = 1;
for (int bit = LG - 1; bit >= 0; bit--) {
int b = num >> bit & 1;
if (!son[p][b]) {
son[p][b] = ++tot;
}
p = son[p][b];
cnt[p]++;
}
}
int find_max(int num) {
int p = 1, ans = 0;
for (int bit = LG - 1; bit >= 0; bit--) {
int b = num >> bit & 1;
if (cnt[son[p][!b]]) {
ans |= 1 << bit;
p = son[p][!b];
} else {
p = son[p][b];
}
}
return ans;
}
int find_min(int num) {
int p = 1, ans = 0;
for (int bit = LG - 1; bit >= 0; bit--) {
int b = num >> bit & 1;
if (cnt[son[p][b]]) {
p = son[p][b];
} else {
ans |= 1 << bit;
p = son[p][!b];
}
}
return ans;
}
图论
Tarjan
scc
vector<int>dfn(n + 1),low(n + 1);
vector<int>scc(n + 1);
int sccCnt = 0,dn = 0;
stack<int> stk;
function<void(int)> dfs = [&](int u) {
dfn[u] = low[u] = ++ dn;
stk.push(u);
for(auto v : adj[u]) {
if(!dfn[v]) {
dfs(v);
low[u] = min(low[u],low[v]);
}else if(!scc[v]) {// 判横插边
low[u] = min(low[u],dfn[v]);
}
}
// SCC 缩点
if(dfn[u] == low[u]) {
sccCnt += 1;
int now = -1;
do{
now = stk.top();
stk.pop();
scc[now] = sccCnt;
}while(now != u);
}
};
e-DCC
vector<int> dfn(n + 1),low(n + 1);
vector<int> dcc(n + 1);
stack<int> stk;
int dn = 0, dccCnt = 0;
function<void(int,int)> dfs = [&](int u,int fa) {
dfn[u] = low[u] = ++ dn;
stk.push(u);
int tim = 0;
for(auto v : adj[u]) if(v != fa) {
if(!dfn[v]) {
dfs(v,u);
low[u] = min(low[u],low[v]);
// find bridge,if we need
// if(low[v] > dfn[u]) {}
}else low[u] = min(low[u],dfn[v]);
}else if(++ tim > 1) low[u] = min(low[u],dfn[v]);// 判重边
// e-DCC 缩点
if(dfn[u] == low[u]) {
int now;
dccCnt += 1;
do {
now = stk.top();
stk.pop();
dcc[now] = dccCnt;
}while(now != u);
}
};
v-DCC
vector<int> dfn(n + 1),low(n + 1);
vector<bool>cut(n + 1);
vector<vector<int>> dcc;//点双得扔桶里,不能直接染色
stack<int> stk;
int dccCnt = 0, dn = 0;
function<void(int,int)> dfs = [&](int u,int fa) {
dfn[u] = low[u] = ++ dn;
stk.push(u);
int child = 0;
for(auto v : adj[u]) if(v != fa) {
if(!dfn[v]) {
child += 1;
dfs(v,u);
low[u] = min(low[v],low[u]);
// 缩点
vector<int> t;
if(low[v] >= dfn[u]) {
dccCnt += 1;
int now;
do {
now = stk.top();
stk.pop();
t.push_back(now);
}while(now != v);
t.push_back(u);
dcc.push_back(t);
if(fa or child > 1) cut[u] = 1;
}
}else low[u] = min(low[u], dfn[v]);
}
if(!fa and child == 0) cut[u] = 1;
};
杂
圆形交
struct Cir {
int x, y, r;
};
double get(Cir &A, Cir &B) {
double d = sqrt((1ll*A.x - B.x) * (A.x - B.x) + (1ll*A.y - B.y) * (A.y - B.y));
int r1 = A.r, r2 = B.r;
if (d >= r1 + r2) return 0;
if (r1 > r2) {
swap(r1, r2);
}
if (r2 - r1 >= d) return PI * r1 * r1;
double x = acos((1ll * r1 * r1 + d * d - 1ll * r2 * r2) / (2ll * r1 * d));
double y = acos((1ll * r2 * r2 + d * d - 1ll * r1 * r1) / (2ll * r2 * d));
return x * r1 * r1 + y * r2 * r2 - sin(x) * d * r1;
}
圆类
位置判断,两圆覆盖弧长
using PDD = pair<double,double>;
struct Circle {
int x,y;
int r;
bool isIn(Circle &B) {
double dx = x - B.x, dy = y - B.y;
double dis = getDis(B);
return B.r - (dis + r) >= eps;
}
bool awayFrom(Circle &B) {
return getDis(B) - (r + B.r) >= eps;
}
double getDis(Circle &B) {
double dx = x - B.x, dy = y - B.y;
return sqrt(dx*dx + dy*dy);
}
vector<PDD> cover(Circle &B) {// A 覆盖 B (弧长)
Circle A = {x,y,r};
double dis = getDis(B);
// r1*r1-r2*r2 = (x+y)*(x-y) dis = x+y
double t1 = B.r*B.r - A.r*A.r;
double y = 0.5 * (dis + t1 / dis);
double theta = acos(y / B.r);
double dx = A.x - B.x, dy = A.y - B.y;
double beta = atan2(dy,dx);// [-PI,PI]
beta = fmod(beta + PI * 2,2 * PI); // [0,2PI]
double l = beta - theta, r = beta + theta;
l = fmod(l + 2 * PI,2 * PI);
r = fmod(r + 2 * PI,2 * PI);
if(r >= l + eps) {// [l,r]
return vector{PDD(l,r)};
}
// [0,r],[l,2PI]
return vector<PDD>{PDD(0,r),PDD(l,2 * PI)};
}
};
哈希
双哈希
// Hash
const int mod1 = 1e9 + 7;
const int mod2 = 1e9 + 9;
typedef pair<int,int> Hash;
Hash B,pw[MAXN];
Hash operator+ (Hash lv,Hash rv){
int x = lv.first + rv.first, y = lv.second + rv.second;
if(x >= mod1) x -= mod1;
if(y >= mod2) y -= mod2;
return make_pair(x,y);
}
Hash operator- (Hash lv,Hash rv){
int x = lv.first - rv.first, y = lv.second - rv.second;
if(x < 0) x += mod1;
if(y < 0) y += mod2;
return make_pair(x,y);
}
Hash operator* (Hash lv,Hash rv){
return make_pair(1ll * lv.first * rv.first % mod1, 1ll * lv.second * rv.second % mod2);
}
void hashInit() {
B = Hash(rnd(mod1), rnd(mod2));
pw[0] = Hash(1,1);
for(int i = 1;i < MAXN;i ++) pw[i] = pw[i - 1] * B;
}
// --Hash-END--