• c++算法竞赛常用板子集合(持续更新)


    前言

    本文主要包含算法竞赛一些常用的板子,码风可能不是太好,还请见谅。

    后续会继续补充没有的板子。当然我太菜了有些可能写不出来T^T

    稍微有些分类但不多,原谅我QwQ

    建议 Ctrl + F 以快速查找板子。

    常用板子

    快速读入

    点击查看代码
    #define ll long long
    inline ll read() {
    	ll s = 0, w = 1;
    	char c = getchar();
    	while (c < '0' || c > '9') {if (c == '-') w = -1; c = getchar();}
    	while (c >= '0' && c <= '9') s = (s << 3) + (s << 1) + (c ^ 48), c = getchar();
    	return s * w;
    }
    

    高精加法

    点击查看代码
    struct node {
    	int c[N], l;
    	node() {l = 0;}
    	void print() {
    		for (int i = l; i >= 1; i--) printf("%d", c[i]);
    		printf("\n");
    	}
    } a, b, ans;
    node operator +(const node &a, const node &b) {
    	node res; res.l = max(a.l, b.l);
    	for (int i = 1; i <= res.l; i++) res.c[i] = a.c[i] + b.c[i];
    	for (int i = 1; i < res.l; i++) res.c[i + 1] += res.c[i] / 10, res.c[i] %= 10;
    	while (res.c[res.l] > 9) res.c[res.l + 1] = res.c[res.l] / 10, res.c[res.l] %= 10, res.l++;
    	while (res.c[res.l] == 0 && res.l > 1) res.l--;
    	return res;
    }
    

    高精减法

    点击查看代码
    struct node {
    	int c[N], l;
    	node() {l = 0;}
    	void print() {
    		for (int i = l; i >= 1; i--) printf("%d", c[i]);
    		printf("\n");
    	}
    } a, b, ans;
    node operator -(const node &a, const node &b) {
    	node res; res.l = max(a.l, b.l);
    	for (int i = 1; i <= res.l; i++) res.c[i] = a.c[i] - b.c[i];
    	for (int i = 1; i < res.l; i++)
    		if (res.c[i] < 0) res.c[i] += 10, res.c[i + 1]--;
    	while (res.c[res.l] == 0 && res.l > 1) res.l--;
    	return res;
    }
    bool operator >(const node &a, const node &b) {
    	if (a.l != b.l) return a.l > b.l;
    	for (int i = a.l; i >= 1; i--) 
    		if (a.c[i] != b.c[i]) return a.c[i] > b.c[i];
    	return 0;
    }
    
    if (b > a) printf("-"), ans = b - a;
    else ans = a - b;
    

    高精乘法

    点击查看代码
    struct node {
    	int c[N], l;
    	node() {l = 0;}
    	void print() {
    		for (int i = l; i >= 1; i--) printf("%d", c[i]);
    		printf("\n");
    	}
    } a, b, ans;
    node operator *(const node &a, const node &b) {
    	node res; res.l = a.l + b.l - 1;
    	for (int i = 1; i <= a.l; i++)
    		for (int j = 1; j <= b.l; j++)
    			res.c[i + j - 1] += a.c[i] * b.c[j];
    	for (int i = 1; i < res.l; i++) res.c[i + 1] += res.c[i] / 10, res.c[i] %= 10;
    	while (res.c[res.l] > 9) res.c[res.l + 1] += res.c[res.l] / 10, res.c[res.l] %= 10, res.l++;
    	while (res.c[res.l] == 0 && res.l > 1) res.l--;
    	return res;
    }
    

    树状数组

    点击查看代码
    // 此处为查询区间和的树状数组。
    int bit[500010];
    void add(int k, int x) {
    	while (k <= n) {
    		bit[k] += x;
    		k += lowbit(k);
    	}
    }
    int ask(int k) {
    	int res = 0;
    	while (k) {
    		res += bit[k];
    		k -= lowbit(k);
    	}
    	return res;
    }
    

    线段树

    点击查看代码
    // 此处为区间修改区间查询区间和的线段树。
    struct SegmentTree {
    	ll sum[N << 2], lazy[N << 2];
    	int l[N << 2], r[N << 2];
    	void update(int rt) {
    		sum[rt] = sum[rt << 1] + sum[rt << 1 | 1];
    	}
    	void pushdown(int rt) {
    		if (!lazy[rt]) return ;
    		sum[rt << 1] += (r[rt << 1] - l[rt << 1] + 1) * lazy[rt], lazy[rt << 1] += lazy[rt];
    		sum[rt << 1 | 1] += (r[rt << 1 | 1] - l[rt << 1 | 1] + 1) * lazy[rt], lazy[rt << 1 | 1] += lazy[rt];
    		lazy[rt] = 0;
    		update(rt);
    	}
    	void build(int rt, int L, int R) {
    		l[rt] = L, r[rt] = R;
    		if (L == R) {
    			sum[rt] = a[L];
    			return ;
    		}
    		int mid = L + R >> 1;
    		build(rt << 1, L, mid), build(rt << 1 | 1, mid + 1, R);
    		update(rt);
    	}
    	void change(int rt, int L, int R, int x) {
    		if (L <= l[rt] && r[rt] <= R) {
    			sum[rt] += (r[rt] - l[rt] + 1) * x;
    			lazy[rt] += x;
    			return ;
    		}
    		pushdown(rt);
    		if (L <= r[rt << 1]) change(rt << 1, L, R, x);
    		if (l[rt << 1 | 1] <= R) change(rt << 1 | 1, L, R, x);
    		update(rt);
    	}
    	ll query(int rt, int L, int R) {
    		if (L <= l[rt] && r[rt] <= R) return sum[rt];
    		pushdown(rt);
    		ll res = 0;
    		if (L <= r[rt << 1]) res += query(rt << 1, L, R);
    		if (l[rt << 1 | 1] <= R) res += query(rt << 1 | 1, L, R);
    		return res;
    	}
    } tree;
    

    动态开点线段树

    点击查看代码
    // 此处为区间修改区间查询区间和的动态开点线段树。
    struct SegmentTree {
    	int l[N << 1], r[N << 1], ls[N << 1], rs[N << 1], cnt; ll sum[N << 1], lazy[N << 1];
    	void update(int rt) {sum[rt] = sum[ls[rt]] + sum[rs[rt]];}
    	int build(int L, int R) {
    		cnt++;
    		l[cnt] = L, r[cnt] = R, sum[cnt] = 0, lazy[cnt] = 0;
    		return cnt;
    	}
    	void pushdown(int rt) {
    		if (lazy[rt] == 0) return ;
    		lazy[ls[rt]] += lazy[rt], lazy[rs[rt]] += lazy[rt];
    		sum[ls[rt]] += lazy[rt] * (r[ls[rt]] - l[ls[rt]] + 1);
    		sum[rs[rt]] += lazy[rt] * (r[rs[rt]] - l[rs[rt]] + 1);
    		lazy[rt] = 0;
    	}
    	void change(int rt, int L, int R, int x) {
    		if (r[rt] < L || R < l[rt]) return ;
    		if (L <= l[rt] && r[rt] <= R) {sum[rt] += x * (r[rt] - l[rt] + 1); lazy[rt] += x; return ;}
    		pushdown(rt);
    		int mid = l[rt] + r[rt] >> 1;
    		if (L <= mid) {
    			if (!ls[rt]) ls[rt] = build(l[rt], mid);
    			change(ls[rt], L, R, x);
    		}
    		if (mid + 1 <= R) {
    			if (!rs[rt]) rs[rt] = build(mid + 1, r[rt]);
    			change(rs[rt], L, R, x);
    		}
    		update(rt);
    	}
    	ll query(int rt, int L, int R) {
    		if (r[rt] < L || R < l[rt]) return 0;
    		if (L <= l[rt] && r[rt] <= R) return sum[rt];
    		pushdown(rt);
    		int mid = l[rt] + r[rt] >> 1; ll res = 0;
    		if (L <= mid) {
    			if (!ls[rt]) ls[rt] = build(l[rt], mid);
    			res += query(ls[rt], L, R);
    		}
    		if (mid + 1 <= R) {
    			if (!rs[rt]) rs[rt] = build(mid + 1, r[rt]);
    			res += query(rs[rt], L, R);
    		}
    		return res;
    	}
    } tree;
    

    扫描线

    点击查看代码
    //此处为统计矩阵总覆盖面积的扫描线
    const int N = 100010;
    int n; 
    struct node {
    	int l, r, h, tag;
    	bool operator <(const node &a) {return h < a.h;}
    } lne[N << 1]; int lcnt;
    int tx[N << 1], tcnt;
    struct SegmentTree {
    	int l[N << 4], r[N << 4]; ll sum[N << 4], len[N << 4];
    	void update(int rt) {
    		if (sum[rt]) len[rt] = tx[r[rt] + 1] - tx[l[rt]];
    		else len[rt] = len[rt << 1] + len[rt << 1 | 1];
    	}
    	void build(int rt, int L, int R) {
    		l[rt] = L, r[rt] = R;
    		if (L == R) {sum[rt] = len[rt] = 0; return ;}
    		int mid = L + R >> 1;
    		build(rt << 1, L, mid), build(rt << 1 | 1, mid + 1, R);
    		update(rt);
    	}
    	void add(int rt, int L, int R, int x) {
    		if (tx[r[rt] + 1] <= L || R <= tx[l[rt]]) return ;
    		if (L <= tx[l[rt]] && tx[r[rt] + 1] <= R) {sum[rt] += x; update(rt); return ;}
    		add(rt << 1, L, R, x), add(rt << 1 | 1, L, R, x);
    		update(rt);
    	}
    } tree;
    
    n = read();
    	for (int i = 1; i <= n; i++) {
    		int xa = read(), ya = read(), xb = read(), yb = read();
    		tx[++tcnt] = xa, tx[++tcnt] = xb;
    		lne[++lcnt].l = xa, lne[lcnt].r = xb, lne[lcnt].h = ya, lne[lcnt].tag = 1;
    		lne[++lcnt].l = xa, lne[lcnt].r = xb, lne[lcnt].h = yb, lne[lcnt].tag = -1;
    	} 
    	sort(tx + 1, tx + 1 + tcnt); tcnt = unique(tx + 1, tx + 1 + tcnt) - tx - 1;
    	sort(lne + 1, lne + 1 + lcnt);
    	tree.build(1, 1, tcnt - 1); 
    	for (int i = 1; i < lcnt; i++) {
    		tree.add(1, lne[i].l, lne[i].r, lne[i].tag);
    		ans += tree.len[1] * (lne[i + 1].h - lne[i].h); 
    	}
    	printf("%lld\n", ans);
    

    点击查看代码
    ll q[N], cnt;
    void pushup(int id) {
    	while (id > 1) {
    		if (q[id] >= q[id >> 1]) break;
    		swap(q[id], q[id >> 1]);
    		id >>= 1;
    	}
    }
    void movedown() {
    	int id = 1;
    	while (id << 1 <= cnt) {
    		if ((id << 1 | 1) <= cnt) {
    			if (q[id] < min(q[id << 1], q[id << 1 | 1])) break;;
    			if (q[id << 1] < q[id << 1 | 1]) swap(q[id], q[id << 1]), id <<= 1;
    			else swap(q[id], q[id << 1 | 1]), id = id << 1 | 1;
    		}
    		else {
    			if (q[id] > q[id << 1]) swap(q[id], q[id << 1]);
    			break;
    		}
    	}
    }
    void add(ll x) {
    	q[++cnt] = x;
    	pushup(cnt);
    }
    void pop() {
    	swap(q[1], q[cnt]);
    	cnt--;
    	movedown();
    }
    

    并查集

    点击查看代码
    struct Disjoint_Set {
    	int p[N], size[N];
    	void build() {
    		for (int i = 1; i <= n; i++) p[i] = i, size[i] = 1;
    	}
    	int root(int x) {
    		if (p[x] != x) return p[x] = root(p[x]);
    		return x;
    	}
    	void merge(int x, int y) {
    		x = root(x), y = root(y);
    		if (size[x] > size[y]) swap(x, y);
    		p[x] = y;
    		size[y] += size[x];
    	}
    	bool check(int x, int y) {
    		x = root(x), y = root(y);
    		return x == y;
    	}
    } a;
    

    ST表

    点击查看代码
    // 代码实现查询区间 $[l, r]$ 的区间最大值
    for (int i = 1; i <= n; i++) st[0][i] = a[i];
    for (int j = 1; j <= lg; j++) {
    	for (int i = 1; i <= n - (1 << j) + 1; i++) {
    		st[j][i] = max(st[j - 1][i], st[j - 1][i + (1 << (j - 1))]);
    	}
    }
    int l, r, lg2, len;
    for (int i = 1; i <= m; i++) {
    	l = read(), r = read();
    	lg2 = log2(r - l + 1);
    	len = 1 << lg2;
    	printf("%d\n", max(st[lg2][l], st[lg2][r - len + 1]));
    }
    

    边链表

    点击查看代码
    const int N = 100010;
    int last[N], cnt;
    struct edge {
    	int to, next, w;
    } e[N << 1];
    void addedge(int x, int y, int w) {
    	e[++cnt].to = y;
    	e[cnt].next = last[x];
    	e[cnt].w = w;
    	last[x] = cnt;
    }
    

    LCA (Tarjan法) 更多方法

    点击查看代码
    struct Disjoint_Set {
    	int p[N], size[N];
    	void build() {
    		for (int i = 1; i <= n; i++) p[i] = i, size[i] = 1;
    	}
    	int root(int x) {
    		if (p[x] != x) return p[x] = root(p[x]);
    		return x;
    	}
    	void merge(int x, int y) {
    		x = root(x), y = root(y);
    		if (size[x] > size[y]) swap(x, y);
    		p[x] = y;
    		size[y] += size[x];
    	}
    	bool check(int x, int y) {
    		x = root(x), y = root(y);
    		return x == y;
    	}
    } a;
    int last[N], cnt;
    struct edge {
    	int to, next;
    } e[N << 1];
    void addedge(int x, int y) {
    	e[++cnt].to = y;
    	e[cnt].next = last[x];
    	last[x] = cnt;
    }
    struct node {
    	int x, y, ans;
    } ask[N];
    vector <int> g[N];
    int p[N];
    bool vis[N];
    int r[N];
    void dfs(int x, int f) {
    	p[x] = f;
    	for (int i = last[x]; i; i = e[i].next) {
    		int v = e[i].to;
    		if (v == f) continue;
    		vis[v] = 1;
    		for (int j : g[v]) {
    			int o = ask[j].x;
    			if (o == v) o = ask[j].y;
    			if (!vis[o]) continue;
    			ask[j].ans = r[a.root(o)]; 
    		}
    		dfs(v, x);
    		a.merge(x, v);
    		r[a.root(x)] = x;
    	}
    }
    

    单源最短路 (堆优化Dijkstra)

    点击查看代码
    void dij(int s) {
    	priority_queue , greater > q; 
    	memset(dis, 0x7f7f7f7f, sizeof(dis));
    	q.push({0, s});
    	dis[s] = 0;
    	while (!q.empty()) {
    		pii u = q.top(); q.pop();
    		int pos = u.second;
    		if (vis[pos]) continue;
    		vis[pos] = 1;
    		for (int j = last[pos]; j; j = e[j].next) {
    			int v = e[j].to;
    			if (vis[v]) continue;
    			if (dis[pos] + e[j].w < dis[v]) dis[v] = dis[pos] + e[j].w, q.push({dis[v], v});
    		}
    	}
    }
    

    缩点

    点击查看代码
    int dfn[N], low[N], dcnt, p[N], sum[N];
    bool instack[N];
    stack <int> s;
    void dfs(int x) {
    	dfn[x] = low[x] = ++dcnt;
    	instack[x] = 1; s.push(x);
    	for (int i = oldg.last[x]; i; i = oldg.e[i].next) {
    		int v = oldg.e[i].to;
    		if (dfn[v]) {
    			if (instack[v]) low[x] = min(low[x], dfn[v]);
    			continue;
    		}
    		dfs(v);
    		low[x] = min(low[x], low[v]);
    	}
    	if (low[x] >= dfn[x]) {
    		p[x] = x, sum[x] = a[x];
    		instack[x] = 0;
    		while (s.top() != x) {
    			int v = s.top(); s.pop();
    			instack[v] = 0;
    			p[v] = x, sum[x] += a[v];
    		}
    		s.pop();
    	}
    }
    
    for (int i = 1; i <= m; i++) u[i] = read(), v[i] = read();
    for (int i = 1; i <= m; i++) oldg.addedge(u[i], v[i]);
    for (int i = 1; i <= n; i++)
    	if (!dfn[i]) dfs(i);
    for (int i = 1; i <= m; i++) 
    	if (p[u[i]] != p[v[i]]) newg.addedge(p[u[i]], p[v[i]]);
    

    点双连通分量

    点击查看代码
    int dfn[N], low[N], tcnt;
    vector <int> ans[N]; int anscnt;
    stack <int> s;
    void dfs(int x, int fa) {
    	dfn[x] = low[x] = ++tcnt;
    	if (x == fa && !last[x]) {
    		ans[++anscnt].emplace_back(x);
    		return ; 
    	}
    	s.push(x);
    	for (int i = last[x]; i; i = e[i].next) {
    		int v = e[i].to;
    		if (dfn[v]) {low[x] = min(low[x], dfn[v]); continue;}
    		dfs(v, x);
    		low[x] = min(low[x], low[v]);
    		if (low[v] >= dfn[x]) {
    			anscnt++;
    			int now;
    			do {
    				now = s.top(); s.pop();
    				ans[anscnt].emplace_back(now);
    			} while (now != v);
    			ans[anscnt].emplace_back(x); 
    		}
    	}
    }
    
    for (int i = 1; i <= m; i++) {
    	int x = read(), y = read();
    	if (x == y) continue;
    	addedge(x, y), addedge(y, x);
    }
    for (int i = 1; i <= n; i++)
    	if (!dfn[i]) dfs(i, i);
    printf("%d\n", anscnt);
    for (int i = 1; i <= anscnt; i++) {
    	printf("%d ", ans[i].size());
    	for (int x: ans[i]) printf("%d ", x);
    	puts("");
    }
    

    边双连通分量

    点击查看代码
    int low[N << 1], dfn[N << 1], tcnt;
    vector <int> ans[N]; int anscnt;
    stack <int> s;
    void dfs(int x, int edg) {
    	dfn[x] = low[x] = ++tcnt;
    	s.push(x);
    	for (int i = last[x]; i; i = e[i].next) {
    		int v = e[i].to;
    		if (dfn[v]) {if (i != (edg ^ 1)) low[x] = min(low[x], dfn[v]); continue;}
    		dfs(v, i);
    		low[x] = min(low[x], low[v]);
    		if (low[v] > dfn[x]) {
    			anscnt++;
    			int now;
    			do {
    				now = s.top(); s.pop();
    				ans[anscnt].emplace_back(now);
    			} while (now != v);
    		}
    	}
    }
    
    for (int i = 1; i <= n; i++)
    	if (!dfn[i]) {
    		addedge(i + n, i), addedge(i, i + n);
    		dfs(i + n, 0);
    	}
    printf("%d\n", anscnt);
    for (int i = 1; i <= anscnt; i++) {
    	printf("%d ", ans[i].size());
    	for (int x: ans[i]) printf("%d ", x);
    	puts("");
    }
    

    欧拉路径

    点击查看代码
    int st[N], ed[N];
    struct edge {
    	int u, v;
    } e[N << 1];
    int rd[N], cd[N];
    bool cmp(edge x, edge y) {
    	if (x.u != y.u) return x.u < y.u;
    	return x.v < y.v;
    }
    int ans[N << 1], cnt;
    void dfs(int x) {
    	while (st[x] <= ed[x]) {
    		st[x]++;
    		dfs(e[st[x] - 1].v);
    	}
    	ans[++cnt] = x;
    }
    

    网络最大流(dinic)

    点击查看代码
    int dep[N], cur[N];
    queue <int> q;
    bool bfs() {
    	while (q.size()) q.pop();
    	for (int i = 1; i <= n; i++) dep[i] = -1; dep[s] = 0;
    	cur[s] = last[s]; q.push(s);
    	while (q.size()) {
    		int x = q.front(); q.pop();
    		for (int i = last[x]; i; i = e[i].next) {
    			int v = e[i].to;
    			if (dep[v] != -1) continue;
    			if (e[i].w == 0) continue;
    			dep[v] = dep[x] + 1;
    			cur[v] = last[v];
    			if (v == t) return 1;
    			q.push(v);
    		}
    	}
    	return 0;
    }
    ll dfs(int x, ll tp) {
    	if (x == t) return tp;
    	ll res = 0;
    	for (int i = cur[x]; i && res < tp; i = e[i].next) {
    		cur[x] = i;
    		int v = e[i].to;
    		if (dep[v] != dep[x] + 1) continue;
    		if (e[i].w == 0) continue;
    		ll now = dfs(v, min(e[i].w, tp - res));
    		if (now == 0) dep[v] = -1;
    		e[i].w -= now, e[i ^ 1].w += now, res += now;
    	}
    	return res;
    }
    ll dinic() {
    	ll res = 0, now;
    	while (bfs()) 
    		while (now = dfs(s, INF)) res += now;
    	return res; 
    }
    

    乘法逆元

    点击查看代码
    fac[0] = fac[1] = 1;
    for (int i = 2; i <= n; i++) fac[i] = fac[i - 1] * i % mod;
    inv[1] = 1;
    for (int i = 2; i <= n; i++) inv[i] = (mod - mod / i) * inv[mod % i] % mod;
    

    快速幂

    点击查看代码
    ll qpow(ll a, ll b) {
    	ll res = 1;
    	while (b) {
    		if (b & 1) res = res * a % mod;
    		a = a * a % mod;
    		b >>= 1;
    	}
    	return res;
    }
    

    矩阵快速幂

    点击查看代码
    struct Martix {
    	int n, m;
    	ll a[N][N];
    	void clear() {memset(a, 0, sizeof(a));}
    	void init() {clear(); for (int i = 1; i <= n; i++) a[i][i] = 1;}
    	Martix operator *(const Martix b) const {
    		Martix res; res.clear(); res.n = n, res.m = b.m;
    		for (int i = 1; i <= res.n; i++)
    			for (int j = 1; j <= res.m; j++)
    				for (int k = 1; k <= m; k++)
    					res.a[i][j] = (res.a[i][j] + a[i][k] * b.a[k][j] % mod) % mod;
    		return res;
    	}
    	Martix operator ^(ll x) const {
    		Martix res, a = *this; res.n = res.m = n, res.init(); 
    		while (x) {
    			if (x & 1) res = res * a;
    			a = a * a;
    			x >>= 1;
    		} 
    		return res;
    	}
    } a;
    

    线性基

    点击查看代码
    int p[N];
    void add(ll x) {
    	for (int i = N; i >= 0; i--) {
    		if (!(x & (1ll << i))) continue;
    		if (p[i]) x ^= p[i];
    		else {p[i] = x; return ;}
    	}
    }
    

    线性筛

    点击查看代码
    int prime[6000010], cnt;
    bool isprime[N + 10];
    void prim() {
    	isprime[0] = isprime[1] = 1;
    	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;
    		}
    	}
    }
    

    字符串哈希

    点击查看代码
    int Char(char c) {
    	if (c >= '0' && c <= '9') return c - '0' + 1; //0~9: 1~10
    	if (c >= 'a' && c <= 'z') return c - 'a' + 11; //a~z: 11~37
    	if (c >= 'A' && c <= 'Z') return c - 'A' + 38; //A~Z: 38~65
    	return 0;
    }
    map int> mp;
    
    cin >> s;
    ll x = 0;
    for (int i = 0; i < s.size(); i++) x = (x * 100) + Char(s[i]);
    mp[x] = 1;
    

    KMP

    点击查看代码
    // s 和 t 为需要匹配的两个 char 类型数组。
    // border[i] 表示 t 长度为 i 的前缀最长的 border 长度。
    ls = strlen(s + 1), lt = strlen(t + 1);
    int j = 0;
    for (int i = 2; i <= lt; i++) {
    	while (j >= 1 && t[j + 1] != t[i]) j = border[j];
    	if (t[j + 1] == t[i]) j++;
    	border[i] = j;
    }
    int sx = 1, tx = 0;
    while (sx <= ls) {
    	while (tx >= 1 && s[sx] != t[tx + 1]) tx = border[tx];
    	if (t[tx + 1] == s[sx]) tx++;
    	if (tx == lt) printf("%d\n", sx - lt + 1);
    	sx++;
    }
    

    AC自动机

    点击查看代码
    struct Trie {
    	int id[27], cnt, fail;
    } t[N];
    void Build(string &s) {
    	int now = 0;
    	for (int i = 0; i < s.size(); i++) {
    		if (!t[now].id[s[i] - 'a']) t[now].id[s[i] - 'a'] = ++cnt;
    		now = t[now].id[s[i] - 'a'];
    	}
    	t[now].cnt++;
    }
    void Fail() {
    	queue <int> q;
    	for (int i = 0; i < 26; i++) {
    		int v = t[0].id[i];
    		if (v != 0) {
    			t[v].fail = 0;
    			q.push(v);
    		}
    	}
    	while (!q.empty()) {
    		int u = q.front(); q.pop();
    		for (int i = 0; i < 26; i++) {
    			int v = t[u].id[i];
    			if (v != 0) {
    				t[v].fail = t[t[u].fail].id[i];
    				q.push(v);
    			}
    			else t[u].id[i] = t[t[u].fail].id[i];
    		}
    	}
    }
    string s;
    int ans;
    void Query() {
    	int now = 0;
    	for (int i = 0; i < s.size(); i++) {
    		now = t[now].id[s[i] - 'a'];
    		for (int to = now; to; to = t[to].fail) {
    			if (t[to].cnt == -1) break;
    			ans += t[to].cnt;
    			t[to].cnt = -1;
    		}
    	}
    }
    

    字符串哈希

    点击查看代码
    int Char(char c) {
    	if (c >= '0' && c <= '9') return c - '0' + 1; //0~9: 1~10
    	if (c >= 'a' && c <= 'z') return c - 'a' + 11; //a~z: 11~37
    	if (c >= 'A' && c <= 'Z') return c - 'A' + 38; //A~Z: 38~65
    	return 0;
    }
    map int> mp;
    
    cin >> s;
    ll x = 0;
    for (int i = 0; i < s.size(); i++) x = (x * 100) + Char(s[i]);
    mp[x] = 1;
    

    KMP

    点击查看代码
    // s 和 t 为需要匹配的两个 char 类型数组。
    // border[i] 表示 t 长度为 i 的前缀最长的 border 长度。
    ls = strlen(s + 1), lt = strlen(t + 1);
    int j = 0;
    for (int i = 2; i <= lt; i++) {
    	while (j >= 1 && t[j + 1] != t[i]) j = border[j];
    	if (t[j + 1] == t[i]) j++;
    	border[i] = j;
    }
    int sx = 1, tx = 0;
    while (sx <= ls) {
    	while (tx >= 1 && s[sx] != t[tx + 1]) tx = border[tx];
    	if (t[tx + 1] == s[sx]) tx++;
    	if (tx == lt) printf("%d\n", sx - lt + 1);
    	sx++;
    }
    
  • 相关阅读:
    T31开发笔记:metaipc测试
    电脑重装系统后DirectX12旗舰版禁用了怎么解决?
    阿里云云数据库Redis的核心概念以及正确购买姿势(十五)
    JavaScript:获取实时年份、月份、日期
    交换机和路由器技术-25-OSPF多区域配置
    React——form的校验和验证规则(使用formik,yup)
    设计模式-装饰器模式(Decorator)
    GO-SLAM——论文简析
    Scrapy爬虫框架实战
    牛客NC98 判断t1树中是否有与t2树完全相同的子树【simple 深度优先dfs C++/Java/Go/PHP】
  • 原文地址:https://www.cnblogs.com/shiranui/p/16817296.html