Data Structure 数据结构
并查集
struct DSU {
int n;
vector<int> fa, rank;
DSU(int n_ = 0) : n(n_), fa(n_ + 1), rank(n_ + 1) {
iota(fa.begin(), fa.end(), 0);
}
int find(int x) {
return x == fa[x] ? x : fa[x] = find(fa[x]);
}
void merge(int x, int y) {
x = find(x), y = find(y);
if(x == y) return ;
if(rank[x] < rank[y]) fa[x] = y;
else {
fa[y] = x;
if(rank[x] == rank[y]) rank[x]++;
}
}
};
二叉树
二叉树的重建
- 已知前序、中序,求后序
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
struct BTree {
int data;
BTree* lson;
BTree* rson;
BTree(int c) {
data = c;
lson = rson = nullptr;
}
};
void preTravel(BTree* rt) {
if(rt == nullptr) return ;
printf("%lld ", rt -> data);
preTravel(rt -> lson);
preTravel(rt -> rson);
}
void midTravel(BTree* rt) {
if(rt == nullptr) return ;
midTravel(rt -> lson);
printf("%lld ", rt -> data);
midTravel(rt -> rson);
}
void postTravel(BTree* rt) {
if(rt == nullptr) return ;
postTravel(rt -> lson);
postTravel(rt -> rson);
printf("%lld ", rt -> data);
}
BTree* reBuild(int* pre, int* mid, int len) {
BTree* root = new BTree(pre[0]);
int id = 0;
while(mid[id] != pre[0]) ++id;
if(id > 0) {
root -> lson = reBuild(pre + 1, mid, id);
}
if(id < len - 1) {
root -> rson = reBuild(pre + id + 1, mid + id + 1, len - id - 1);
}
return root;
}
int main(){
int n;
cin >> n;
int pre[n]{}, mid[n]{};
for(int i = 0;i < n;i++) cin >> pre[i];
for(int i = 0;i < n;i++) cin >> mid[i];
BTree* root = reBuild(pre, mid, n);
postTravel(root);
printf("\n");
return 0;
}
线段树
加法线段树
template<typename T>
struct segTree {
int n;
vector<T> tr, tag;
segTree(int n_ = 0) : n(n_), tr(n_ << 2), tag(n_ << 2) {}
void up(int rt) {
return ;
}
void down(int rt, int l, int r) {
if(tag[rt]) {
int mid = l + r >> 1;//lson -> [l, mid], rson -> [mid + 1, r]
}
return ;
}
void build(int rt, int l, int r){
if(l == r){
return ;
}
int mid = l + r >> 1;
build(rt << 1, l, mid);
build(rt << 1 | 1, mid + 1, r);
up(rt);
return ;
}
void modify(int rt, int l, int r, int val, int L, int R) {
if(l <= L && R <= r) {
return ;
}
down(rt, L, R);
int mid = L + R >> 1;
if(mid >= l) modify(rt << 1, l, r, val, L, mid);
if(mid < r) modify(rt << 1 | 1, l, r, val, mid + 1, R);
up(rt);
return ;
}
T query(int rt, int l, int r, int L, int R){
if(l <= L && R <= r) return tr[rt];
down(rt, L, R);
int mid = L + R >> 1;
T ret{};
if(l <= mid) ret += query(rt << 1, l, r, L, mid);
if(r > mid) ret += query(rt << 1 | 1, l, r, mid + 1, R);
return ret;
}
};
乘法线段树
const int p = 1e9 + 7;
struct segTree {
int n;
vector<ll> tr, f, mf;
segTree(int n_ = 0) : n(n_), tr(n_ << 2, 0), f(n_ << 2, 0), mf(n_ << 2, 1) {
}
void up(int rt) {
tr[rt] = (tr[rt << 1] + tr[rt << 1 | 1]) % p;
return ;
}
void down(int rt, int l, int r) {
int mid = l + r >> 1;
tr[rt << 1] = (tr[rt << 1] * mf[rt] % p + f[rt] * (mid - l + 1)) % p;
tr[rt << 1 | 1] = (tr[rt << 1 | 1] * mf[rt] % p + f[rt] * (r - mid)) % p;
mf[rt << 1] = mf[rt << 1] * mf[rt] % p;
mf[rt << 1 | 1] = mf[rt << 1 | 1] * mf[rt] % p;
f[rt << 1] = (f[rt << 1] * mf[rt] + f[rt]) % p;
f[rt << 1 | 1] = (f[rt << 1 | 1] * mf[rt] + f[rt]) % p;
f[rt] = 0, mf[rt] = 1;
return ;
}
void build(int rt, int l, int r){
if(l == r){
cin >> tr[rt];
return ;
}
int mid = l + r >> 1;
build(rt << 1, l, mid);
build(rt << 1 | 1, mid + 1, r);
up(rt);
return ;
}
void modify(int rt, int l, int r, ll v, ll mv, int L, int R) {
if(l <= L && R <= r) {
mf[rt] = mf[rt] * mv % p;
f[rt] = (f[rt] * mv + v) % p;
tr[rt] = (tr[rt] * mv + v * (R - L + 1) % p) % p;
return ;
}
down(rt, L, R);
int mid = L + R >> 1;
if(mid >= l) modify(rt << 1, l, r, v, mv, L, mid);
if(mid < r) modify(rt << 1 | 1, l, r, v, mv, mid + 1, R);
up(rt);
return ;
}
ll query(int rt, int l, int r, int L, int R){
if(l <= L && R <= r) return tr[rt];
down(rt, L, R);
int mid = L + R >> 1;
ll ret = 0;
if(l <= mid) ret = (ret + query(rt << 1, l, r, L, mid)) % p;
if(r > mid) ret = (ret + query(rt << 1 | 1, l, r, mid + 1, R)) % p;
return ret;
}
};
最值线段树
struct segTree {
int n;
vector<int> min_, f;
segTree(int n_ = 0) : n(n_), min_(n_ << 2, 0), f(n_ << 2, 0) {}
inline void up(int rt) {
min_[rt] = min(min_[rt << 1], min_[rt << 1 | 1]);
}
inline void down(int rt, int l, int r) {
if(f[rt]) {
f[rt << 1] += f[rt];
f[rt << 1 | 1] += f[rt];
min_[rt << 1] -= f[rt];
min_[rt << 1 | 1] -= f[rt];
f[rt] = 0;
}
return ;
}
void build(int rt, int l, int r) {
if(l == r) {
cin >> min_[rt];
return ;
}
int mid = l + r >> 1;
build(rt << 1, l, mid);
build(rt << 1 | 1, mid + 1, r);
up(rt);
return ;
}
void modify(int rt, int l, int r, int val, int L, int R) {
if(l <= L && R <= r) {
min_[rt] -= val;
f[rt] += val;
return ;
}
down(rt, L, R);
int mid = L + R >> 1;
if(mid >= l) modify(rt << 1, l, r, val, L, mid);
if(mid < r) modify(rt << 1 | 1, l, r, val, mid + 1, R);
up(rt);
return ;
}
int query(int rt, int l, int r, int L, int R) {
if(l <= L && R <= r) return min_[rt];
down(rt, L, R);
int mid = L + R >> 1;
int ret = 0x3f3f3f3f;
if(l <= mid) ret = min(ret, query(rt << 1, l, r, L, mid));
if(r > mid) ret = min(ret, query(rt << 1 | 1, l, r, mid + 1, R));
up(rt);
return ret;
}
void debug(int rt, int l, int r) {
printf("l = %d, r = %d, min_[rt] = %d, f[rt] = %d\n", l, r, min_[rt], f[rt]);
if(l == r) return ;
int mid = l + r >> 1;
debug(rt << 1, l, mid);
debug(rt << 1 | 1, mid + 1, r);
}
};
树状数组
一维树状数组
正常的树状数组(单点更新,区间求和)
template<typename T>
struct Fenwick {
int n;
vector<T> tr;
Fenwick(int n_ = 0) : n(n_), tr(n_ + 1) {}
void add(int x, int v_) {
if(!x) { tr[x] += v_; return ; }
while(x <= n) tr[x] += v_, x += x & -x;
}
T query(int x) {
T ans(tr[0]);
while(x) ans += tr[x], x -= x & -x;
return ans;
}
};
二维树状数组
struct Fenwick {
int n, m;
vector<vector<int> > tr;
Fenwick() {}
Fenwick(int n_, int m_) : n(n_), m(m_), tr(n << 1, vector<int>(m_ << 1, 0)) {}
void add(int xx, int yy, int val) {
for(int x = xx;x <= n;x += x & -x) {
for(int y = yy;y <= m;y += y & -y) {
tr[x][y] += val;
}
}
}
int query(int xx, int yy){
int ret = 0;
for(int x = xx;x > 0;x -= x & -x) {
for(int y = yy;y > 0;y -= y & -y) {
ret += tr[x][y];
}
}
return ret;
}
};
RMQ(倍增法)
ST表(前置芝士)
f [ j ] [ i ] < = = > j → j + 2 i f[j][i]<==>j\to{j+2^i} f[j][i]<==>j→j+2i
struct SparseTable { // a_ : [1, n]
int n;
vector<vector<int> > St;
vector<int> lg;
SparseTable(const vector<int>& a_, int n_) : n(n_), St(n_ << 1, vector<int>(20, 0)), lg(n_ << 1) {
for(int i = 2;i <= n;i++) lg[i] = lg[i >> 1] + 1;
for(int i = 1;i <= n;i++) St[i][0] = a_[i];
for(int j = 1;j <= lg[n];j++) {
for(int i = 1;i + (1 << j) - 1 <= n;i++) {
St[i][j] = __gcd(St[i][j - 1], St[i + (1 << (j - 1))][j - 1]);
}
}
}
int query(int l, int r) {
int x = lg[r - l + 1];
return __gcd(St[l][x], St[r - (1 << x) + 1][x]);
}
};
树链剖分
重链剖分
const int maxn = 2e5 + 7;
struct segTree {
//@author Zjkai
int l, r;
ll val, f;
}tr[maxn << 2];
struct Edge {
int ne, to, w;
}edge[maxn];
vector<int> head(maxn, -1);
vector<int> fa(maxn, 0), dep(maxn, 0), son(maxn, 0), size(maxn, 0); //dfs_1
// 每个点的父亲//深度数组//重儿子数组//子树大小数组
vector<int> L(maxn, 0), invL(maxn, 0), top(maxn, 0); //dfs_2
// DFN // DFN中对应的点//重链顶
vector<int> pi(maxn, 0);
//点权
int tot = 0, n, m, r, p, Time = 0;
void add(int fr, int to, int cost) {
++tot;
edge[tot].ne = head[fr];
edge[tot].to = to;
edge[tot].w = cost;
head[fr] = tot;
}
void up(int rt) {
tr[rt].val = tr[rt << 1].val + tr[rt << 1 | 1].val;
}
void down(int rt){
if(tr[rt].f) {
tr[rt << 1].val += tr[rt].f * (tr[rt << 1].r - tr[rt << 1].l + 1);
tr[rt << 1 | 1].val += tr[rt].f * (tr[rt << 1 | 1].r - tr[rt << 1 | 1].l + 1);
tr[rt << 1].f += tr[rt].f;
tr[rt << 1 | 1].f += tr[rt].f;
tr[rt].f = 0;
}
return ;
}
void build(int rt, int l, int r){
tr[rt].l = l, tr[rt].r = r, tr[rt].f = 0;
if(l == r){
tr[rt].val = pi[invL[l]];
return ;
}
int mid = l + r >> 1;
build(rt << 1, l, mid);
build(rt << 1 | 1, mid + 1, r);
up(rt);
return ;
}
void modify(int rt, int l, int r, int val) {//修改子树
if(tr[rt].l >= l && tr[rt].r <= r) {
tr[rt].val += (tr[rt].r - tr[rt].l + 1) * val;
tr[rt].f += val;
return ;
}
down(rt);
int mid = tr[rt].l + tr[rt].r >> 1;
if(mid >= l) modify(rt << 1, l, r, val);
if(mid < r) modify(rt << 1 | 1, l, r, val);
up(rt);
return ;
}
ll query(int rt, int l, int r){//查询子树
if(tr[rt].l >= l && tr[rt].r <= r) return tr[rt].val;
down(rt);
int mid = tr[rt].l + tr[rt].r >> 1;
ll ret = 0;
if(l <= mid) ret += query(rt << 1, l, r);
if(r > mid) ret += query(rt << 1 | 1, l, r);
return ret;
}
void dfs_1(int now) {//预处理1
size[now] = 1;
dep[now] = dep[fa[now]] + 1;
for(int i = head[now];i != -1;i = edge[i].ne) {
int to = edge[i].to;
if(to != fa[now]) {
fa[to] = now;
dfs_1(to);
size[now] += size[to];
if(size[to] > size[son[now]]) son[now] = to;
}
}
return ;
}
void dfs_2(int now, int tp) {// 预处理2
L[now] = ++Time;
invL[Time] = now;
top[now] = tp;
if(son[now]) dfs_2(son[now], tp);
for(int i = head[now];i != -1;i = edge[i].ne) {
int to = edge[i].to;
if(to != fa[now] && to != son[now]) {
dfs_2(to, to); //轻链的顶就是自己!
}
}
return ;
}
ll getsum(int x, int y) {//得到简单路径的长度
ll ret = 0;
while(top[x] != top[y]) {
if(dep[top[x]] < dep[top[y]]) swap(x, y);
ret = ret + query(1, L[top[x]], L[x]);
x = fa[top[x]];
}
if(L[x] > L[y]) swap(x, y);
return ret + query(1, L[x], L[y]);
}
void upd(int x, int y, int val) {//修改简单路径
while(top[x] != top[y]) {
if(dep[top[x]] < dep[top[y]]) swap(x, y);
modify(1, L[top[x]], L[x], val);
x = fa[top[x]];
}
if(L[x] > L[y]) swap(x, y);
modify(1, L[x], L[y], val);
}
分块|根号分治
分块
template<typename T>
struct Sqrt_DivideConquer {
int n, len;
vector<T> a, belong, L, R, tag, sum;
Sqrt_DivideConquer(int n_ = 0, const vector<T> &a_ = {}) : belong(n_ + 1){
n = n_, a = a_, len = sqrt(n_);
L.resize(len << 1), R.resize(len << 1);
tag.resize(len << 1), sum.resize(len << 1);
for(int i = 1;i <= len + 1;i++) {
L[i] = n / len * (i - 1) + 1;
R[i] = min(n / len * i, n_);
for(int j = L[i];j <= R[i];j++) {
belong[j] = i;
sum[i] += a_[j];
}
}
}
void add(int l, int r, T val) {
if(belong[l] == belong[r]) {
for(int i = l;i <= r;i++) {
a[i] += val;
sum[belong[i]] += val;
}
}
else {
for(int i = l;i <= R[belong[l]];i++) {
a[i] += val;
sum[belong[i]] += val;
}
for(int i = L[belong[r]];i <= r;i++) {
a[i] += val;
sum[belong[i]] += val;
}
for(int i = belong[l] + 1;i < belong[r];i++) {
tag[i] += val;
}
}
return ;
}
T query(int l, int r) {
T ret{};
if(belong[l] == belong[r]) {
for(int i = l;i <= r;i++) {
ret += a[i] + tag[belong[i]];
}
}
else {
for(int i = l;i <= R[belong[l]];i++) {
ret += a[i] + tag[belong[i]];
}
for(int i = L[belong[r]];i <= r;i++) {
ret += a[i] + tag[belong[i]];
}
for(int i = belong[l] + 1;i < belong[r];i++) {
ret += (R[i] - L[i] + 1) * tag[i] + sum[i];
}
}
return ret;
}
};
莫队
- 处理区间问题暴力首选
#include<bits/stdc++.h>
using namespace std;
using ll = long long;
const int maxn = 1e5 + 7;
struct Off {
int l, r;
int id;
};
void add(int x) {
}
void sub(int x) {
}
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int n, m, res = 0;
cin >> n >> m;
res = 0;
vector<int> a(n + 1, 0), cnt(maxn, 0), ans(m + 1, 0);
vector<int> bl(n + 1, 0);//块的编号
vector<Off> q(m + 1); //离线
int size_ = (int)(sqrt(n));
for(int i = 1;i <= n;i++) {
cin >> a[i];
cnt[a[i]]++;
bl[i] = i / size_;
}
for(int i = 1;i <= m;i++) {
cin >> q[i].l >> q[i].r;
q[i].id = i;
}
sort(q.begin() + 1, q.end(), [&](Off x, Off y) {
if(bl[x.l] == bl[y.l]) return x.r < y.r;
return bl[x.l] < bl[y.l];
});
int l = 1, r = 0;
for(int i = 1;i <= m;i++) {
q[i].l += 1, q[i].r -= 1;
while(q[i].l < l) sub(--l);
while(q[i].r > r) sub(++r);
while(q[i].l > l) add(l++);
while(q[i].r < r) add(r--);
ans[q[i].id] = res;
}
for(int i = 1;i <= m;i++) cout << ans[i] << '\n';
return 0;
}
堆
FHQ-Treap(无旋树堆)
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
const int maxn = 1e5 + 7;
mt19937 rng(chrono::system_clock::now().time_since_epoch().count());
struct Node {
int val;
int l, r, size, Priority;
}tr[maxn << 2];
int tot, Root, n, x, opt;
int create(int key) {
int root = ++tot;
tr[root].val = key;
tr[root].size = 1;
tr[root].l = tr[root].r = 0;
tr[root].Priority = rng();
return root;
}
void pushup(int root) {
tr[root].size = tr[tr[root].l].size + tr[tr[root].r].size + 1;
}
void split(int root, int key, int &x, int &y) {
if (root == 0) {
x = y = 0;
return;
}
if (tr[root].val <= key) {
x = root;
split(tr[root].r, key, tr[root].r, y);
}
else {
y = root;
split(tr[root].l, key, x, tr[root].l);
}
pushup(root);
}
int merge(int x, int y) {
if (x == 0 || y == 0) return x + y;
if (tr[x].Priority > tr[y].Priority) {
tr[x].r = merge(tr[x].r, y);
pushup(x);
return x;
}
else {
tr[y].l = merge(x, tr[y].l);
pushup(y);
return y;
}
}
void insert(int key) {
int x, y;
split(Root, key - 1, x, y);
Root = merge(merge(x, create(key)), y);
}
void remove(int key) {
int x, y, z;
split(Root, key, x, z);
split(x, key - 1, x, y);
y = merge(tr[y].l, tr[y].r);
Root = merge(merge(x, y), z);
}
int getRank(int key) {
int x, y, ans;
split(Root, key - 1, x, y);
ans = tr[x].size + 1;
Root = merge(x, y);
return ans;
}
int kth(int r) {
int root = Root;
while (true) {
if (tr[tr[root].l].size + 1 == r) {
break;
}
else if (tr[tr[root].l].size + 1 > r) {
root = tr[root].l;
}
else {
r -= tr[tr[root].l].size + 1;
root = tr[root].r;
}
}
return tr[root].val;
}
int lower(int key) {
int x, y, root, ans;
split(Root, key - 1, x, y);
root = x;
while (tr[root].r) root = tr[root].r;
ans = tr[root].val;
Root = merge(x, y);
return ans;
}
int upper(int key) {
int x, y, root, ans;
split(Root, key, x, y);
root = y;
while (tr[root].l) root = tr[root].l;
ans = tr[root].val;
Root = merge(x, y);
return ans;
}
int main() {
scanf("%d", &n);
for (int i = 1; i <= n; ++i) {
scanf("%d %d", &opt, &x);
if (opt == 1) insert(x);
if (opt == 2) remove(x);
if (opt == 3) printf("%d\n", getRank(x));
if (opt == 4) printf("%d\n", kth(x));
if (opt == 5) printf("%d\n", lower(x));
if (opt == 6) printf("%d\n", upper(x));
}
return 0;
}
可持久化数据结构
可持久化线段树
- 给定 n 个整数构成的序列 a,将对于指定的闭区间[l, r]查询其区间内的第 k 小值。
#include<bits/stdc++.h>
using namespace std;
using ll = long long;
const int maxn = 1e5 + 7;
struct HJT {
int l, r, val;
}tr[maxn << 5];
vector<int> rt(maxn, 0), a(maxn, 0), lsh;
int cnt = 0;
void insert(int pre, int& now, int l, int r, int x) {
tr[++cnt] = tr[pre];
now = cnt;
tr[now].val++;
if(l == r) return ;
int mid = l + r >> 1;
if(x <= mid) insert(tr[pre].l, tr[now].l, l, mid, x);
else insert(tr[pre].r, tr[now].r, mid + 1, r, x);
return ;
}
int query(int L, int R, int l, int r, int k) {
if(l == r) return l;
int mid = l + r >> 1;
int tmp = tr[tr[R].l].val - tr[tr[L].l].val;
if(k <= tmp) return query(tr[L].l, tr[R].l, l, mid, k);
else return query(tr[L].r, tr[R].r, mid + 1, r, k - tmp);
}
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int n;
cin >> n;
for(int i = 1;i <= n;i++) cin >> a[i];
for(int i = 1;i <= n;i++) lsh.push_back(a[i]);
sort(lsh.begin(), lsh.end());
lsh.erase(unique(lsh.begin(), lsh.end()), lsh.end());
map<int, int> mp;
for(int i = 0;i < lsh.size();i++) mp[lsh[i]] = i + 1;
for(int i = 1;i <= n;i++) insert(rt[i - 1], rt[i], 1, n, mp[a[i]]);
int m;
cin >> m;
for(int i = 1;i <= m;i++) {
int l, r, k;
cin >> l >> r >> k;
l += 1, r += 1;
//k = r - l + 2 - k; //第k大
//k; //第k小
cout << lsh[query(rt[l - 1], rt[r], 1, n, k) - 1] << '\n';
}
return 0;
}
可持久化数组
-
在某个历史版本上修改某一个位置上的值
-
访问某个历史版本上的某一位置的值(对于操作2,即为生成一个完全一样的版本,不作任何改动)
#include<bits/stdc++.h>
using namespace std;
using ll = long long;
const int maxn = 1e6 + 7;
struct node {
int l, r, val;
}tr[maxn * 20];
vector<int> rt(maxn, 0);
int cnt = 0;
void build(int& p, int l, int r) {
p = ++cnt;
if(l == r) {
cin >> tr[p].val;
return ;
}
int mid = l + r >> 1;
build(tr[p].l, l, mid);
build(tr[p].r, mid + 1, r);
return ;
}
void insert(int pre, int &now, int l, int r, int loc, int x) {
now = ++cnt;
tr[now] = tr[pre];
if(l == r) {
tr[now].val = x;
return ;
}
int mid = l + r >> 1;
if(loc <= mid) insert(tr[pre].l, tr[now].l, l, mid, loc, x);
else insert(tr[pre].r, tr[now].r, mid + 1, r, loc, x);
}
int query(int now, int l, int r, int x) {
if(l == r) return tr[now].val;
int mid = l + r >> 1;
if(x <= mid) return query(tr[now].l, l, mid, x);
else return query(tr[now].r, mid + 1, r, x);
}
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int n, m;
cin >> n >> m;
build(rt[0], 1, n);
for(int i = 1;i <= m;i++) {
int ver, op, loc;
cin >> ver >> op >> loc;
if(op == 1) {
int x;
cin >> x;
insert(rt[ver], rt[i], 1, n, loc, x);
}
else {
cout << query(rt[ver], 1, n, loc) << '\n';
rt[i] = rt[ver];
}
}
return 0;
}