【模板】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;
}

浙公网安备 33010602011771号