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--
posted @ 2022-04-12 22:59  Mxrurush  阅读(98)  评论(0编辑  收藏  举报