Datastruct 数据结构

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]<==>jj+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;
}

可持久化并查集

可持久化FHQ-Treap

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值