【模板】ccpc板子库

字符串

KMP

#include<bits/stdc++.h>
#define N 1000010
#define fo(a, b, c) for(int b = a; b <= c; b++)
using namespace std;
int n, m, b[N];
string s, t; 
int main(){
	ios::sync_with_stdio(0);
	cin.tie(0); cout.tie(0);
	cin >> s >> t;
	n = s.size(), s = " " + s;
	m = t.size(), t = " " + t;
	for(int i = 2, j = 0; i <= m; i++){
		while(j && t[i] != t[j + 1]) j = b[j];
		if(t[j + 1] == t[i]) j++;
		b[i] = j;
	}
	for(int i = 1, j = 0; i <= n; i++){
		while(j && t[j + 1] != s[i]) j = b[j];
		if(t[j + 1] == s[i]) j++;
		if(j == m){
			cout << i - j + 1 << "\n";
			j = b[j];
		}
	}
	fo(1, i, m) cout << b[i] << ' '; 
	return 0;
}

Manacher

#include<bits/stdc++.h>
#define N 22000010
#define fo(a, b, c) for(int b = a; b <= c; b++)
using namespace std;
int n, id, mx, p[N], ans = 0;
char a[N], ch[N];
int main(){
	ios::sync_with_stdio(0);
	cin.tie(0); cout.tie(0);
	ch[0] = '~';
	cin >> a + 1, n = strlen(a + 1);
	fo(1, i, n) ch[2 * i] = a[i];
	fo(1, i, n + 1) ch[2 * i - 1] = '#';
	n = n * 2 + 1;
	mx = 0, id = 0;
	fo(1, i, n){
		if(i <= mx) p[i] = min(p[id * 2 - i], mx - i + 1); 
		else p[i] = 1;
		while(ch[i + p[i]] == ch[i - p[i]]) ++p[i];
		if(p[i] + i - 1 > mx) mx = i + p[i] - 1, id = i;
		ans = max(ans, p[i] - 1);
	}
	cout << ans;
	return 0;
}

图论

Tarjan

强连通分量

#include<bits/stdc++.h>
#define pb push_back
#define N 10010
#define Fo(a, b) for(auto a : b) 
#define fo(a, b, c) for(int b = a; b <= c; b++)
using namespace std;
int n, m, dfn[N], low[N], tim, in[N], vis[N], tt, belong[N];
stack<int>st;
vector<int>G[N], scc[N]; 
void tarjan(int u){
	dfn[u] = low[u] = ++tim, in[u] = 1;
	st.push(u);
	Fo(v, G[u]){
		if(!dfn[v]){
			tarjan(v);
			low[u] = min(low[u], low[v]);
		}
		else if(in[v]) low[u] = min(low[u], dfn[v]);
	}
	if(low[u] == dfn[u]){
		++tt;
		int v = st.top();
		while(v != u){
			belong[v] = tt, in[v] = 0;
			scc[tt].pb(v);
			st.pop(), v = st.top();
		}
		belong[v] = tt, in[v] = 0;
		scc[tt].pb(v);
		st.pop();
	}
}
int main(){
	ios::sync_with_stdio(0);
	cin.tie(0); cout.tie(0);
	cin >> n >> m;
	fo(1, i, m){
		int x, y; cin >> x >> y;
		G[x].pb(y);
	}
	fo(1, i, n) if(!dfn[i]) tarjan(i);
	cout << tt << "\n";
	fo(1, i, n){
		if(vis[belong[i]]) continue;
		int u = belong[i];
		vis[u] = 1;
		sort(scc[u].begin(), scc[u].end());
		Fo(v, scc[u]) cout << v << ' ';
		cout << "\n";
	}
	return 0;
} 

点双联通分量

#include<bits/stdc++.h>
#define N 2000010
#define fo(a, b, c) for(int b = a; b <= c; b++)
#define Fo(a, b) for(auto a : b)
#define pb push_back
using namespace std;
int n, m, dfn[N], low[N], tim, tt, rt;
vector<int>G[N], scc[N];
stack<int>st;
void tarjan(int u){
	dfn[u] = low[u] = ++tim;
	st.push(u);
	int son = 0;
	Fo(v, G[u]){
		if(!dfn[v]){
			++son;
			tarjan(v);
			low[u] = min(low[u], low[v]);
			if(low[v] >= dfn[u]){
				++tt;
				int x = st.top();
				while(x != u){
					scc[tt].pb(x);
					st.pop(), x = st.top();
				}
				//st.pop(); 
				//scc[tt].pb(v) 
				scc[tt].pb(u);
			}
		}
		else low[u] = min(low[u], dfn[v]);
	} 
	if(!son && u == rt) scc[++tt].pb(u);
}
int main(){
	ios::sync_with_stdio(0);
	cin.tie(0); cout.tie(0);
	cin >> n >> m;
	fo(1, i, m){
		int x, y; cin >> x >> y;
		G[x].pb(y), G[y].pb(x);
	}
	fo(1, i, n) if(!dfn[i]){
		while(!st.empty()) st.pop();
		rt = i, tarjan(i);
	}
	//fo(1, i, n) if(!G[i].size()) scc[++tt].pb(i);
	cout << tt << "\n";
	fo(1, i, tt){
		cout << scc[i].size() << ' ';
		Fo(x, scc[i]) cout << x << ' ';
		cout << "\n";
	}
	return 0; 
}

边双联通分量

#include<bits/stdc++.h>
#define N 2000010
#define pb push_back
#define fo(a, b, c) for(int b = a; b <= c; b++)
#define Fo(a, b) for(auto a : b)  
using namespace std;
int n, m, dfn[N], low[N], tim;
int e[N], tt, vis[N]; 
struct edge{
	int id, v;
};
vector<edge>G[N];
vector<int>scc[N];
void tarjan(int u, int fa){
	dfn[u] = low[u] = ++tim;
	Fo(to, G[u]){
		int id = to.id, v = to.v;
		if(!dfn[v]){
			tarjan(v, id);
			low[u] = min(low[u], low[v]);
			if(low[v] > dfn[u]) e[id] = 1;
		}
		else if(id != fa) low[u] = min(low[u], dfn[v]);
	}
}
void dfs(int u){
	scc[tt].pb(u), vis[u] = 1;
	Fo(to, G[u]){
		int v = to.v, id = to.id;
		if(e[id] || vis[v]) continue;
		dfs(v);
	}
}
int main(){
	ios::sync_with_stdio(0);
	cin.tie(0); cout.tie(0);
	cin >> n >> m;
	fo(1, i, m){
		int x, y; cin >> x >> y;
		G[x].pb({i, y}), G[y].pb({i, x});
	}
	fo(1, i, n) if(!dfn[i]) tarjan(i, 0);
	fo(1, i, n) if(!vis[i]){
		++tt, dfs(i);
	}
	cout << tt << "\n";
	fo(1, i, tt){
		cout << scc[i].size() << ' ';
		Fo(x, scc[i]) cout << x << ' ';
		cout << "\n";
	}
	return 0;
}

树论

点分治

#include<bits/stdc++.h>
#define Fo(a, b) for(auto a : b)
#define fo(a, b, c) for(int b = a; b <= c; b++)
#define pb push_back
#define INF 2147483647
#define N 10000010
using namespace std;
struct node{
	int v, w;
};
int n, m, q[N];
int sz[N], mx[N], rt, s, dis[N], t[N];
bool vis[N], f[N];
vector<node>e[N];
vector<int>d, rec;
void get(int u, int fa){
	sz[u] = 1, mx[u] = 0;
	Fo(to, e[u]){
		if(to.v == fa || vis[to.v]) continue;
		get(to.v, u);
		sz[u] += sz[to.v];
		mx[u] = max(mx[u], sz[to.v]);
	}
	mx[u] = max(mx[u], s - sz[u]);
	if(mx[u] < mx[rt]) rt = u;
} 
void getd(int u, int fa){
	d.pb(dis[u]);
	Fo(to, e[u]){
		if(to.v == fa || vis[to.v]) continue;
		dis[to.v] = dis[u] + to.w;
		getd(to.v, u);
	}
}
void calc(int u){
	rec.clear();
	Fo(to, e[u]){
		if(vis[to.v]) continue;
		d.clear(), dis[to.v] = to.w, getd(to.v, u);
		Fo(x, d){
			fo(1, i, m)
				if(q[i] >= x) t[i] |= f[q[i] - x];  			
		}
		Fo(x, d) rec.pb(x), f[x] = 1;
	}
	Fo(x, rec) f[x] = 0;
}
void solve(int u){
	vis[u] = f[0] = 1;
	calc(u);
	Fo(to, e[u]){
		if(vis[to.v]) continue;
		s = sz[to.v], mx[rt = 0] = INF, get(to.v, 0);
		solve(rt);
	}
}
int main(){
	ios::sync_with_stdio(0);
	cin.tie(0); cout.tie(0);
	cin >> n >> m;
	fo(1, i, n - 1){
		int u, v, w; cin >> u >> v >> w;
		e[u].pb((node){v, w}), e[v].pb((node){u, w});
	}
	fo(1, i, m) cin >> q[i];
	mx[rt = 0] = INF, s = n, get(1, 0);
	solve(rt);
	fo(1, i, m){
		if(t[i]) cout << "AYE" << endl;
		else cout << "NAY" << endl;
	}
	return 0;
}

虚树

#include<bits/stdc++.h>
#define N 1000010
#define INF 2147483647
#define int long long
using namespace std;
int n, m, h[N];
int cnt = 0, head[N], Head[N], Cnt = 0;
int tim, f[N][30], dep[N], d[N][30], dfn[N], dp[N];
bool vis[N];
struct edge{
	int to, next, w;
}e[N << 2], E[N << 2];
void add(int x, int y, int w){
	e[++cnt].to = y;
	e[cnt].next = head[x];
	e[cnt].w = w;
	head[x] = cnt;
}
void Add(int x, int y, int w){
	E[++Cnt].to = y;
	E[Cnt].w = w;
	E[Cnt].next = Head[x];
	Head[x] = Cnt;
}
void dfs(int u, int fa){
	dep[u] = dep[fa] + 1, dfn[u] = ++tim, f[u][0] = fa;
	for(int i = 1; i <= 20; i++)
		f[u][i] = f[f[u][i - 1]][i - 1], d[u][i] = min(d[u][i - 1], d[f[u][i - 1]][i - 1]);
	for(int i = head[u]; i; i = e[i].next){
		int v = e[i].to, w = e[i].w;
		if(v == fa) continue;
		d[v][0] = w;
		dfs(v, u);
	}
}
signed Lca(int x, int y){
	if(dep[x] < dep[y]) swap(x, y);
	int len = dep[x] - dep[y];
	for(int i = 0; i <= 20; i++){
		if(len & 1) x = f[x][i];
		len >>= 1;
	}
	if(x == y) return x;
	for(int i = 20; i >= 0; i--){
		if(f[x][i] != f[y][i])
			x = f[x][i], y = f[y][i];
	}
	return f[x][0];
}
bool cmp(int x, int y){
	return dfn[x] < dfn[y];
}
void Dp(int u, int fa){
	for(int i = Head[u]; i; i = E[i].next){
		int v = E[i].to, w = E[i].w;
		if(v == fa) continue;
		Dp(v, u);
		if(!vis[v]) dp[u] += min(dp[v], w);
		else dp[u] += w;
	}
}
int calc(int x, int y){
	int len = dep[x] - dep[y];
	int s = INF;
	for(int i = 0; i <= 20; i++){
		if(len & 1){
			s = min(s, d[x][i]);
			x = f[x][i];
		}
		len >>= 1;
	}
	return s;
}
signed main(){
	cin >> n;
	for(int i = 1; i < n; i++){
		int x, y, w;
		cin >> x >> y >> w;
		add(x, y, w), add(y, x, w); 
	}
	tim = 0; dfs(1, 0);
	cin >> m;
	while(m--){
		int k; cin >> k;
		for(int i = 1; i <= k; i++){
			cin >> h[i];
			vis[h[i]] = 1;
		}
		sort(h + 1, h + k + 1, cmp);
		int tot = k;
		for(int i = 1; i < k; i++){
			int lca = Lca(h[i], h[i + 1]);
			h[++tot] = lca;
		}
		h[++tot] = 1;
		sort(h + 1, h + tot + 1, cmp);
		tot = unique(h + 1, h + tot + 1) - h - 1;
		for(int i = 1; i < tot; i++){
			int x = h[i], y = h[i + 1];
			int lca = Lca(x, y);
			int w = calc(y, lca);
			Add(lca, y, w), Add(y, lca, w);
		}
		Dp(1, 0);
		cout << dp[1] << endl;
		Cnt = 0;
		for(int i = 1; i <= tot; i++){
			vis[h[i]] = Head[h[i]] = dp[h[i]] = 0 ;
		}
	}
	return 0;
} 

数据结构

树剖

#include<bits/stdc++.h>
#define maxn 30010
#define int long long
using namespace std;
struct edge{
	int to, next;
}e[maxn << 1];
int cnt = 0, head[maxn];
int a[maxn], n, m;
int t1[maxn << 2], t2[maxn << 2], ans1 = 0, ans2 = 0;
int dep[maxn], size[maxn], top[maxn], f[maxn], id[maxn], tim = 0;
int son[maxn];
char op[maxn];
void add(int x, int y){
	e[++cnt].to = y;
	e[cnt].next = head[x];
	head[x] = cnt;
}
void build(int p, int l, int r){
	if(l == r){
		t1[p] = a[l];
		t2[p] = a[l];
		//cout << l << t1[p] << endl;
		return;
	}
	int mid = (l + r) >> 1;
	int ls = (p << 1), rs = (p << 1) + 1;
	build(ls, l, mid);
	build(rs, mid + 1, r);
	t1[p] = max(t1[ls], t1[rs]);
	t2[p] = t2[ls] + t2[rs];
}
void update(int p, int l, int r, int x, int k){
	if(l == r){
		t1[p] = k;
		t2[p] = k;
		return;
	}
	int mid = (l + r) >> 1;
	int ls = (p << 1), rs = (p << 1) + 1;
	if(x <= mid) update(ls, l, mid, x, k);
	if(x > mid) update(rs, mid + 1, r, x, k);
	t1[p] = max(t1[ls], t1[rs]);
	t2[p] = t2[ls] + t2[rs];
}
void query(int p, int l, int r, int x, int y){
	//cout << l << ' ' << r << endl;
	if(x <= l && r <= y){
		ans1 = max(ans1, t1[p]);
		ans2 += t2[p];
		//cout << p << ' ' << t1[p] << endl;
		return;
	}
	int mid = (l + r) >> 1;
	int ls = (p << 1), rs = (p << 1) + 1;
	//cout << ls << ' ' << rs << endl;
	if(x <= mid) query(ls, l, mid, x, y);
	if(y > mid) query(rs, mid + 1, r, x, y);
}
void dfs1(int u, int fa){
	dep[u] = dep[fa] + 1, size[u] = 1, f[u] = fa;
	int maxson = 0, maxsz = 0;
	for(int i = head[u]; i; i = e[i].next){
		int v = e[i].to;
		if(v == fa) continue;
		dfs1(v, u);
		size[u] += size[v];
		if(size[v] > maxsz){
			maxsz = size[v];
			maxson = v;
		}
	} 
	son[u] = maxson;
}
void dfs2(int u, int fa){
	id[u] = ++tim, top[son[u]] = top[u];
	if(!son[u]) return;
	dfs2(son[u], u);
	for(int i = head[u]; i; i = e[i].next){
		int v = e[i].to;
		if(v == fa) continue;
		if(v == son[u]) continue;
		top[v] = v;
		dfs2(v, u);
	}
}
int lca(int a, int b, int op){
	ans1 = -2147483647, ans2 = 0;
	while(top[a] != top[b]){
		if(dep[top[a]] < dep[top[b]]) swap(a, b);
		query(1, 1, n, id[top[a]], id[a]);
		//cout << ans2 << endl;
		a = f[top[a]];
	}
	if(dep[a] > dep[b]) swap(a, b);
	query(1, 1, n, id[a], id[b]);
	if(op == 1) return ans1;
	return ans2;
}
signed main(){
	ios::sync_with_stdio(0);
	cin.tie(0); cout.tie(0); 
	cin >> n;
	for(int i = 1; i < n; i++){
		int x, y;
		cin >> x >> y;
		add(x, y); add(y, x);
	}
	top[1] = 1;
	dfs1(1, 0);
	dfs2(1, 0);
	//cout << top[2] << endl;
	for(int i = 1; i <= n; i++){
		int x; cin >> x;
		a[id[i]] = x;
	}
	memset(t1, -0x3f, sizeof(t1));
	build(1, 1, n);
	cin >> m;
	//query(1, 1, n, 1, 3);
	//cout << ans2 << endl;
	for(int i = 1; i <= m; i++){
		int x, y;
		cin >> op >> x >> y;
		if(op[0] == 'C'){
			update(1, 1, n, id[x], y);
		}
		if(op[0] == 'Q' && op[1] == 'M'){
			cout << lca(x, y, 1) << endl;
		}
		if(op[0] == 'Q' && op[1] == 'S'){
			cout << lca(x, y, 2) << endl;
		}
	}
	return 0;
}

带权并查集

#include<bits/stdc++.h>
#define fo(a, b, c) for(int b = a; b <= c; b++)
#define N 1000010
using namespace std;
int c, T, n, m;
int fa[N], p[N], from[N], w[N];
int find(int x){
	if(x == fa[x]) return x;
	int tmp = fa[x];
	return fa[x] = find(fa[x]), p[x] ^= p[tmp], fa[x];
}
void solve(){
	cin >> n >> m;
	fo(1, i, n + 2) fa[i] = i, p[i] = 0, from[i] = i, w[i] = 0;
	fo(1, i, m){
		int x, y; char op;
		cin >> op >> x;
		if(op == '+' || op == '-') cin >> y;
		if(op == '+') from[x] = from[y], w[x] = w[y];
		if(op == '-') from[x] = from[y], w[x] = w[y] ^ 1;
		if(op == 'T') from[x] = n + 1, w[x] = 0;
		if(op == 'U') from[x] = n + 2, w[x] = 0;
		if(op == 'F') from[x] = n + 1, w[x] = 1;
	}
	fo(1, i, n){
		int x = i, y = from[i], fx = find(x), fy = find(y);
		if(fx != fy) fa[fx] = fy, p[fx] = p[x] ^ p[y] ^ w[x]; 
		else if(p[x] ^ p[y] ^ w[x]) fa[fx] = n + 2, p[fx] = 0;
	}
	int ans = 0;
	fo(1, i, n){
		if(find(i) == n + 2) ans++;
	}
	cout << ans << "\n";
}
int main(){
	ios::sync_with_stdio(0);
	cin.tie(0); cout.tie(0);
	cin >> c >> T;
	while(T--) solve();
	return 0;
}

笛卡尔树

#include<bits/stdc++.h>
#define N 10000010
#define int long long
#define fo(a, b, c) for(int b = a; b <= c; b++)
using namespace std;
int n, ans1 = 0, ans2 = 0;
struct tree{
	int w, ls, rs, fa;
}t[N];
void insert(int x){
	int i = x - 1;
	while(t[i].w >= t[x].w) i = t[i].fa;
	t[x].fa = i, t[x].ls = t[i].rs;
	t[i].rs = x;
}
signed main(){
	ios::sync_with_stdio(0);
	cin.tie(0); cout.tie(0);
	cin >> n;
	fo(1, i, n){
		cin >> t[i].w; insert(i);
	}
	fo(1, i, n){
		ans1 ^= i * (t[i].ls + 1), ans2 ^= i * (t[i].rs + 1);
	}
	cout << ans1 << " " << ans2 << "\n";
	return 0;
}

FHQ 平衡树

#include<bits/stdc++.h>
#define N 5000010
using namespace std;
struct treenode{
	int siz, ls, rs, pri, val;
}t[N];
int n, m, cnt = 0, rt = 0;
int add(int val){
	t[++cnt].pri = rand(), t[cnt].siz = 1, t[cnt].val = val;
	return cnt;
} 
void pushup(int u){
	t[u].siz = t[t[u].ls].siz + t[t[u].rs].siz + 1;
}
void split(int u, int x, int &L, int &R){
	if(!u) return L = 0, R = 0, void();
	if(t[u].val <= x) L = u, split(t[u].rs, x, t[u].rs, R);
	else R = u, split(t[u].ls, x, L, t[u].ls);
	pushup(u);
}
int merge(int L, int R){
	if(!L || !R) return L | R;
	if(t[L].pri <= t[R].pri) return t[L].rs = merge(t[L].rs, R), pushup(L), L;
	else return t[R].ls = merge(L, t[R].ls), pushup(R), R;
}
void Insert(int val){
	int L, R;
	split(rt, val, L, R), rt = merge(merge(L, add(val)), R);
}
void Delete(int val){
	int L, R, P;
	split(rt, val, L, R), split(L, val - 1, L, P);
	P = merge(t[P].ls, t[P].rs);
	rt = merge(merge(L, P), R);
}
int getrank(int val){
	int L, R, ans;
	split(rt, val - 1, L, R);
	ans = t[L].siz + 1;
	return rt = merge(L, R), ans;
}
int kth(int u, int k){
	int x = t[t[u].ls].siz + 1;
	if(k == x) return t[u].val;
	else if(k > x) return kth(t[u].rs, k - x);
	else return kth(t[u].ls, k);
}
int getpre(int val){
	return kth(rt, getrank(val) - 1);
} 
int getsuc(int val){
	return kth(rt, getrank(val + 1));
}
int main(){
	ios::sync_with_stdio(0);
	cin.tie(0); cout.tie(0);
	cin >> n >> m;
	for(int i = 1; i <= n; i++){
		int val; cin >> val;
		Insert(val);
	}
	int last = 0, ans = 0; 
	while(m--){
		int op, val; cin >> op >> val;
		val ^= last;
		if(op == 1) Insert(val);
		if(op == 2) Delete(val);
		if(op == 3) last = getrank(val), ans ^= last;
		if(op == 4) last = kth(rt, val), ans ^= last;
		if(op == 5) last = getpre(val), ans ^= last;
		if(op == 6) last = getsuc(val), ans ^= last;
	}
	cout << ans;
	return 0;
}

文艺平衡树

#include<bits/stdc++.h>
#define N 300010
using namespace std;
struct node{
	int pri, val, rs, ls, siz;
}t[N];
int n, Min, k, cnt = 0, tot = 0, rt = 0, A = 0;
char op; 
int add(int val){
	t[++cnt].val = val, t[cnt].pri = rand(), t[cnt].siz = 1;
	return cnt;
}
void pushup(int u){
	t[u].siz = t[t[u].ls].siz + t[t[u].rs].siz + 1;
}
void split(int u, int x, int &L, int &R){
	if(!u) return L = 0, R = 0, void(); 
	if(t[u].val <= x) L = u, split(t[u].rs, x, t[u].rs, R);
	else R = u, split(t[u].ls, x, L, t[u].ls);
	//cout << t[u].siz << endl;
	pushup(u);
}
int merge(int L, int R){
	if(!L || !R) return L | R;
	if(t[L].pri < t[R].pri) return t[L].rs = merge(t[L].rs, R), pushup(L), L;
	else return t[R].ls = merge(L, t[R].ls), pushup(R), R; 
}
int kth(int u, int k){
	int x = t[t[u].ls].siz + 1;
	//cout << u << ' ' << x << ' ' << k << endl;
	if(x == k) return t[u].val;
	if(k > x) return kth(t[u].rs, k - x);
	else return kth(t[u].ls, k);
}
void Insert(int val){
	int L, R;
	split(rt, val, L, R);
	rt = merge(merge(L, add(val)), R);
}
int main(){
	ios::sync_with_stdio(0);
	cin.tie(0); cout.tie(0);
	cin >> n >> Min;
	for(int i = 1; i <= n; i++){
		cin >> op >> k;
		if(op == 'I'){
			if(k >= Min){
				++tot;
				Insert(k-A);
			}
		}
		if(op == 'A') A += k;
		if(op == 'S') {
			A -= k;
			int L, R;
			split(rt, Min - 1 - A, L, R);
			//cout << t[rt].siz << endl;
			rt = R;
		}
		if(op == 'F'){
			k = t[rt].siz - k + 1;
			//cout << k << endl;
			if(k <= 0){
				cout << -1 << endl;
				continue;
			}
			cout << kth(rt, k) + A << endl;
		}
	}
	cout << tot - t[rt].siz;
	return 0; 
}

可持久化线段树

#include<bits/stdc++.h>
#define N 30000010
#define fo(a, b, c) for(int b = a; b <= c; b++)
#define _fo(a, b, c) for(int b = a; b >= c; b--)
using namespace std;
int n, m, a[N];
int rt[N], tn = 0;
struct nd{
	int lc, rc, w;
}t[N << 2];
void build(int &p, int l, int r){
	p = ++tn;
	if(l == r){
		return t[p].w = a[l], void(); 
	}
	int md = (l + r) >> 1;
	build(t[p].lc, l, md), build(t[p].rc, md + 1, r);
}
void cpy(int &p){
	++tn, t[tn] = t[p], p = tn;
}
void upd(int &p, int l, int r, int x, int k){
	cpy(p);
	if(l == r){
		return t[p].w = k, void();
	}
	int md = (l + r) >> 1;
	if(x <= md) upd(t[p].lc, l, md, x, k);
	else upd(t[p].rc, md + 1, r, x, k);
}
int query(int p, int l, int r, int x){
	if(l == r) return t[p].w;
	int md = (l + r) >> 1;
	if(x <= md) return query(t[p].lc, l, md, x);
	else return query(t[p].rc, md + 1, r, x);
}
int main(){
	ios::sync_with_stdio(0);
	cin.tie(0); cout.tie(0);
	cin >> n >> m;
	fo(1, i, n) cin >> a[i];
	build(rt[0], 1, n);
	fo(1, i, m){
		int root, op, x, k;
		cin >> root >> op >> x;
		if(op == 1){
			cin >> k;
			rt[i] = rt[root];
			upd(rt[i], 1, n, x, k);
		}
		if(op == 2){
			cout << query(rt[root], 1, n, x) << endl;
			rt[i] = rt[root];
		}
	}
	return 0;
}  

线段树合并

#include<bits/stdc++.h>
#define N 4000010
#define C 100000
#define M N << 2 
#define fo(a, b, c) for(int b = a; b <= c; b++)
#define _fo(a, b, c) for(int b = a; b >= c; b--)
#define Fo(a, b) for(auto a : b)
#define pb push_back
#define int long long
using namespace std;
int n, m, f[N][30], d[N];
int rt[N], lc[M], rc[M], t[M], id[M], tn = 0, ans[N];
vector<int>e[N];
void pushup(int p){
	if(t[lc[p]] > t[rc[p]]) id[p] = id[lc[p]];
	if(t[lc[p]] < t[rc[p]]) id[p] = id[rc[p]];
	if(t[lc[p]] == t[rc[p]]) id[p] = min(id[rc[p]], id[lc[p]]);
	t[p] = max(t[lc[p]], t[rc[p]]);
}
void upd(int &p, int l, int r, int x, int k){
	if(!p) p = ++tn;
	if(l == r){
		return id[p] = x, t[p] += k, void();
	}
	int md = (l + r) >> 1;
	if(x <= md) upd(lc[p], l, md, x, k);
	else upd(rc[p], md + 1, r, x, k);
	pushup(p);
}
void dfs(int u, int fa){
	f[u][0] = fa, d[u] = d[fa] + 1;
	fo(1, i, 20) f[u][i] = f[f[u][i - 1]][i - 1];
	Fo(v, e[u]) if(v ^ fa) dfs(v, u);
}
int Lca(int x, int y){
	if(d[x] < d[y]) swap(x, y);
	int len = d[x] - d[y];
	fo(0, i, 20){
		if(len & 1) x = f[x][i];
		len >>= 1;
	}
	if(x == y) return x;
	_fo(20, i, 0){
		if(f[x][i] ^ f[y][i]) x = f[x][i], y = f[y][i];
	}
	return f[x][0];
}
int mg(int x, int y, int l, int r){
	if(!x || !y) return x | y;
	if(l == r) return t[x] += t[y], x;
	int md = (l + r) >> 1;
	lc[x] = mg(lc[x], lc[y], l, md), rc[x] = mg(rc[x], rc[y], md + 1, r);
	pushup(x);
	return x;
}
void dfs1(int u, int fa){
	Fo(v, e[u]){
		if(v ^ fa){
			dfs1(v, u);
			rt[u] = mg(rt[u], rt[v], 1, C);
		}
	}
	ans[u] = id[rt[u]];
	if(!t[rt[u]]) ans[u] = 0;
}
signed main(){
	ios::sync_with_stdio(0);
	cin.tie(0); cout.tie(0);
	cin >> n >> m;
	fo(1, i, n - 1){
		int x, y; cin >> x >> y;
		e[x].pb(y), e[y].pb(x);
	}
	dfs(1, 0);
	fo(1, i, m){
		int x, y, z; cin >> x >> y >> z;
		upd(rt[x], 1, C, z, 1), upd(rt[y], 1, C, z, 1);
		int l = Lca(x, y);
		//cout << x << ' ' << y << ' ' << l << endl;
		upd(rt[l], 1, C, z, -1), upd(rt[f[l][0]], 1, C, z, -1);
	}
	dfs1(1, 0);
	fo(1, i, n) cout << ans[i] << "\n";
	return 0;
}

STL

bitset

bitset 的声明

\\声明一个大小为 100010 的 bitset
bitset<100010>bs
\\声明一个大小为 5 的 bitset,并将其初始化为 101010(42 的二进制)
\\但是由于 42 的长度大于 5 所以高位会被自动截断
bitset<5>bs(42)

bitset 可以像数组一样用 [] 进行访问,也可以像数组一样更改值,注意 bitset 最低为为 \(0\),且是从右边开始。

bitset 成员函数

单次使用 \(O(1)\) 的成员函数

  • set(pos) 将第 pos 位设为 \(1\)
  • reset(pos) 将第 pos 位设为 \(0\)
  • flip(pos) 翻转第 pos 位。

时间复杂度 \(O(\frac{n}{w})\) 的成员函数

  • set() 将所有位都设置为 1。
  • reset() 将所有位都设置为 0。
  • flip() 翻转所有位。
  • count() 返回值为 1 的位的数量。
  • size() 返回 bitset 的总大小。
  • any() 检查是否有任何一位是 1。
  • none() 检查是否所有位都是 0。
  • all() 检查是否所有位都是 1。

位运算(时间复杂度 \(O(\frac{n}{w})\))

bitset 重载了常见的位运算符,可以方便地在两个 大小相同 的 bitset 之间进行运算。

  • & (与)
  • | (或)
  • ^ (异或)
  • ~(非)
  • <<(左移)
  • >> (右移)

其他技巧

CDQ 分治

#include<bits/stdc++.h>
#define N 200010
#define fo(a, b, c) for(int b = a; b <= c; b++)
#define Fo(a, b) for(auto a : b)
#define lb lower_bound
#define pb push_back
#define lowbit(x) x & (-x)
using namespace std;
struct node{
	int a, b, c, cnt, f;
}a[N], b[N];
int n, k, s[N], f[N], ans[N], tt; 
vector<int>vec;
bool cmp(node x, node y){
	if(x.a == y.a){
		if(x.b == y.b) return x.c < y.c;
		return x.b < y.b;
	}
	return x.a < y.a;
}
bool Cmp(node x, node y){
	return x.b < y.b;
}
void upd(int x, int num){
	while(x <= k){
		s[x] += num, x += lowbit(x);
	}
}
int qry(int x){
	int sum = 0;
	while(x){
		sum += s[x], x -= lowbit(x);
	}
	return sum;
}
void mg(int l, int md, int r){
	sort(b + l, b + md + 1, Cmp);
	sort(b + md + 1, b + r + 1, Cmp);
	int p = l - 1;
	vec.clear();
	fo(md + 1, i, r){
		while(b[p + 1].b <= b[i].b && p < md){
			++p, vec.pb(p);
			upd(b[p].c, b[p].cnt);
		}
		b[i].f += qry(b[i].c);
	}
	Fo(x, vec) upd(b[x].c, -b[x].cnt);
}
void solve(int l, int r){
	if(l == r) return; 
	int md = (l + r) >> 1; 
	solve(l, md), solve(md + 1, r);
	mg(l, md, r);
}
int main(){
	ios::sync_with_stdio(0);
	cin.tie(0); cout.tie(0);
	cin >> n >> k;
	fo(1, i, n) cin >> a[i].a >> a[i].b >> a[i].c;
	sort(a + 1, a + n + 1, cmp);
	fo(1, i, n){
		if(a[i].a != a[i - 1].a || a[i].b != a[i - 1].b || a[i].c != a[i - 1].c) b[++tt] = a[i];
		b[tt].cnt++;
	}  
	solve(1, tt);
	fo(1, i, tt) ans[b[i].f + b[i].cnt - 1] += b[i].cnt; 
	fo(0, i, n - 1) cout << ans[i] << "\n";
	return 0;
} 

差分约束

#include<bits/stdc++.h>
using namespace std;
struct edge{
	int w,to,next;
}e[10010];
int n,m;
int cnt=0,head[5010];
int cnt1[5010],dis[5010];
bool vis[5010];
void add(int x,int y,int w){
	e[++cnt].to=y;
	e[cnt].next=head[x];
	e[cnt].w=w; 
	head[x]=cnt;
}
void spfa(int x){
	queue<int>q;
	memset(vis,0,sizeof(vis));
	memset(cnt1,0,sizeof(cnt1));
	memset(dis,0x3f,sizeof(dis));
	q.push(x);
	cnt1[x]=1;vis[x]=1;
	dis[x]=0;
	while(!q.empty()){
		int u=q.front();
		q.pop();
		vis[u]=0;
		for(int i=head[u];i;i=e[i].next){
			int v=e[i].to;
			int w=e[i].w;
			if(dis[v]>w+dis[u]){
				dis[v]=dis[u]+w;
				if(!vis[v]){
					vis[v]=1;
					q.push(v);
					cnt1[v]++;
					if(cnt1[v]>n){
						printf("NO");
						return;
					}
				}
			}
		}
	}
	for(int i=1;i<=n;i++){
		printf("%d ",dis[i]);
	} 
	return;
}
int main(){
	scanf("%d%d",&n,&m);
	for(int i=1;i<=m;i++){
		int u,v,w;
		scanf("%d%d%d",&u,&v,&w);
		add(v,u,w);
	}
	for(int i=1;i<=n;i++){
		add(n+1,i,0);
	}
	spfa(n+1);
	return 0;
}

dsu on tree

#include<bits/stdc++.h>
#define pb push_back
#define fo(a, b, c) for(int b = a; b <= c; b++)
#define Fo(a, b) for(auto a : b)
#define N 200010
using namespace std;
int n, c[N], f, son[N], sz[N], ans;
int cnt[N], ccnt[N];
vector<int>G[N];
void dfs(int u){
	sz[u] = 1;
	Fo(v, G[u]){
		dfs(v, u);
		sz[u] += sz[v];
		if(sz[v] > sz[son[u]]) son[u] = v;
	}
}
void mdf(int u, int x){
	--ccnt[cnt[c[u]]], cnt[c[u]] += x, ++ccnt[cnt[c[u]]];
}
void add(int u, int x){
	mdf(u, x);
	Fo(v, G[u]) add(v, x);
}
void solve(int u, bool keep){
	Fo(v, G[u]) if(v ^ son[u]) solve(v, 0);
	if(son[u]) solve(son[u], 1);
	mdf(u, 1);
	Fo(v, G[u]) if(v ^ son[u]) add(v, 1);
	if(cnt[c[u]] * ccnt[cnt[c[u]]] == sz[u]) ++ans;
	if(!keep) add(u, - 1);
}
int main(){
	ios::sync_with_stdio(0);
	cin.tie(0); cout.tie(0);
	cin >> n;
	fo(1, i, n){
		cin >> c[i] >> f;
		if(f) G[f].pb(i);
	}
	dfs(1);
	solve(1, 1);
	cout << ans;
	return 0;
} 

区间 mex

#include<bits/stdc++.h>
#define fo(a, b, c) for(int b = a; b <= c; b++)
#define N 200010
#define md ((l + r) >> 1)
#define ls p << 1
#define rs p << 1 | 1
#define lc ls, l, md
#define rc rs, md + 1, r
#define U 1, 0, n
using namespace std;
int n, m, a[N], ans[N];
struct SGT{
	int t[N << 2];
	void upd(int p, int l, int r, int x, int k){
		if(l == r){
			return t[p] = k, void();
		}
		if(x <= md) upd(lc, x, k);
		else upd(rc, x, k); 
		t[p] = min(t[ls], t[rs]);
	}
	int qry(int p, int l, int r, int x){
		if(l == r) return l;
		if(t[ls] < x) return qry(lc, x);
		else return qry(rc, x);
	}
}T;
struct node{
	int id, l, r;
}q[N];
bool cmp(node x, node y){
	return x.r < y.r;
}
int main(){
	cin >> n >> m;
	fo(1, i, n) cin >> a[i];
	fo(1, i, m){
		int l, r; cin >> l >> r;
		q[i] = {i, l, r};
	}
	sort(q + 1, q + m + 1, cmp);
	int lst = 0;
	fo(1, i, m){
		fo(lst + 1, j, q[i].r) if(a[j] <= n) T.upd(U, a[j], j);
		lst = q[i].r;
		ans[q[i].id] = T.qry(U, q[i].l);
	} 
	fo(1, i, m) cout << ans[i] << "\n";
	return 0;
}

WQS 二分

#include<bits/stdc++.h>
#define N 100010
using namespace std;
struct edge{
	int w, x, y;
	bool op;
}e[N << 1];
int n, m, k, head[N], cnt = 0;
int fa[N], ans, tot, sum;
int find(int x){
	if(x == fa[x]) return x;
	return fa[x] = find(fa[x]);
}
bool cmp(edge a, edge b){
	if(a.w == b.w) return a.op < b.op;
	return a.w < b.w;
}
bool check(int x){
	for(int i = 1; i <= m; i++){
		if(e[i].op == 0){
			e[i].w += x;
		}
	}
	for(int i = 1; i <= n + 1; i++) fa[i] = i;
	sort(e + 1, e + m + 1, cmp);
	tot = 0, sum = 0;
	for(int i = 1; i <= m; i++){
		int fax = find(e[i].x), fay = find(e[i].y);
		if(fax != fay){
			sum += e[i].w;
			fa[fax] = fay;
			if(e[i].op == 0) ++tot;
		}
	}
	for(int i = 1; i <= m; i++){
		if(e[i].op == 0){
			e[i].w -= x;
		}
	}
	if(tot >= k){
		ans = sum - x * k;
		return 1;
	}
	return 0;
}
int main(){
	ios::sync_with_stdio(0);
	cin.tie(0); cout.tie(0);
	cin >> n >> m >> k;
	for(int i = 1; i <= m; i++){
		int x, y, w, op;
		cin >> e[i].x >> e[i].y >> e[i].w >> e[i].op;
		++e[i].x, ++e[i].y;
	}
	int l = -111, r = 111;
	while(l < r){
		int mid = (l + r + 1) >> 1;
		if(check(mid)) l = mid;
		else r = mid - 1;
	}
	cout << ans;
	return 0;
}

数学

高精度

基础属性

class __int256
{
private:
	const static int N=2333,base=1e8;//N为压位后最大位数,base为压多少位
	int a[N],len,neg;//a存放int,len存放压位后位数,neg表示是否为负数
}

初始化

和不压位高精度类似的,每次模 base 的余数放进数组,再把这个数不断除以 base

template<typename _Tp>__int256(_Tp x)
{
    memset(a,0,sizeof(a));
    if(x<0)x=-x,neg=1;
    len=0;
    int tmp;
    while((tmp=x/base))
    {
        a[++len]=x%base;
        x=tmp;
    }
    a[++len]=x;
}

比较运算

bool operator==(const __int256& x)const
{
    if(len!=x.len||neg!=x.neg)return false;
    for(int i=1;i<=len;++i)if(a[i]!=x.a[i])return false;
    return true;
}
bool operator!=(const __int256& x)const{return !(*this==x);}
bool operator>(const __int256& x)const
{
    if(neg!=x.neg)return x.neg;
    if(len!=x.len)return len>x.len;
    for(int i=len;i;--i)if(a[i]!=x.a[i])return a[i]>x.a[i];
    return false;
}
bool operator<(const __int256& x)const
{
    if(neg!=x.neg)return neg;
    if(len!=x.len)return len<x.len;
    for(int i=len;i;--i)if(a[i]!=x.a[i])return a[i]<x.a[i];
    return false;
}
bool operator>=(const __int256& x)const{return !(*this<x);}
bool operator<=(const __int256& x)const{return !(*this>x);}

高精加高精

与普通高精加法类似,直接逐位相加,如果有进位就减掉 base 并让下一位加 1
就好,注意最高位进位的处理

__int256 operator+(const __int256& x)const
{
    if((!neg)&&x.neg)return *this-(-x);
    if(neg&&(!x.neg))return x-(-*this);
    __int256 ans=__int256();
    ans.len=std::max(len,x.len);
    for(int i=1;i<=ans.len;++i)
    {
        ans.a[i]+=a[i]+x.a[i];
        if(ans.a[i]>=base)ans.a[i]-=base,++ans.a[i+1];
    }
    if(ans.a[ans.len+1])++ans.len;
    if(neg&&x.neg)ans.neg=1;
    return ans;
}

高精减高精

同样的,只是注意必须要用更大的数减去更小的数,不然借位很难处理,同时前导零也不要忘记去除

__int256 operator-(const __int256& x)const 
{
    if((!neg)&&x.neg)return *this+(-x);
    if(neg&&x.neg)return (-x)-(-*this);
    if(neg&&(!x.neg))return -((-*this)+x);
    __int256 ans=__int256();
    if(*this==x)return ans;
    if(x>*this)
    {
        ans=(x-*this);
        ans.neg=1;
        return ans;
    }
    ans.len=std::max(len,x.len);
    for(int i=1;i<=ans.len;++i)
    {
        ans.a[i]+=a[i]-x.a[i];
        if(ans.a[i]<0)ans.a[i]+=base,--ans.a[i+1];
    }
    while(ans.len&&!ans.a[ans.len])--ans.len;
    return ans;
}

高精乘高精

模拟竖式乘法,乘法分配律逐个相乘相加,复杂度 Θ(len2)
写 FFT 也可以,会更快一点(Θ(lenloglen)),但是我太懒了

__int256 operator*(const __int256& x)const
{
    __int256 ans=__int256();
    if(*this==ans||x==ans)return ans;
    if(neg!=x.neg)ans.neg=1;
    ans.len=std::max(len,x.len);
    ull tmp;
    for(int i=1;i<=len;++i)
        for(int j=1;j<=x.len;++j)
        {
            tmp=1ull*a[i]*x.a[j]+ans.a[i+j-1];
            if(tmp>=base)
            {
                ans.a[i+j]+=tmp/base;
                ans.a[i+j-1]=tmp%base;
            }
            else ans.a[i+j-1]=tmp;
        }
    while(ans.a[ans.len]>0)++ans.len;
    --ans.len;
    return ans;
}

高精乘低精

和高精加法很像,每次临时放在 long long 或者 unsigned long long 暂时存一下就行了

template<typename _Tp>__int256 operator*(const _Tp& x)const
{
    __int256 ans=__int256();
    if(*this==ans||x==0)return ans;
    if(neg!=(x<0))ans.neg=1;
    ans.len=len;
    ull tmp;
    for(int i=1;i<=len;++i)
    {
        tmp=1ull*a[i]*x+ans.a[i];
        if(tmp>=base)
        {
            ans.a[i]=tmp%base;
            ans.a[i+1]+=tmp/base;
        }
        else ans.a[i]=tmp;
    }
    while(ans.a[ans.len]>0)++ans.len;
    --ans.len;
    return ans;
}

高精除低精

直接模拟竖式除法,很简单没什么好说的

template<typename _Tp>__int256 operator/(const _Tp& x)const
{
    if(x==0)std::cerr<<"Error:divide 0\n",exit(-1);
    __int256 ans=__int256();
    if(len==1&&x>a[1])return ans;
    ull res=0;
    if(neg!=(x<0))ans.neg=1;
    for(int i=len;i;--i)
    {
        res=res*base+a[i];
        ans.a[i]=res/x;
        res%=x;
    }
    while(ans.a[ans.len]>0)++ans.len;
    --ans.len;
    return ans;
}

高精除高精

这里利用倍增,把除数倍增然后不断往下减,减掉之后再除以 2
接着减就行,由于使用了高精乘以低精和高精除以除以低精,所以常数会非常大,但是算是比较方便的一种实现了

__int256 operator/(const __int256& X)const
{
    if(X==0)std::cerr<<"Error:divide 0\n",exit(-1);
    __int256 ans(*this),x(X),tmp(1),lt=__int256();
    if(neg!=x.neg)ans.neg=1;
    while(ans>=x) x*=2,tmp*=2;
    while(tmp.len>1||tmp.a[1])
    {
        if(ans>=x) ans-=x,lt+=tmp;
        x/=2,tmp/=2;
    }
    ans=lt;
    while(ans.len&&!ans.a[ans.len])--ans.len;
    if(!ans.len)return __int256();
    return ans;
}
posted @ 2025-11-10 18:16  GuoSN0410  阅读(7)  评论(0)    收藏  举报