← 全部文章

CF571D Campus 题解

本文目录(3 节)
  1. 题意
  2. 题解
  3. 代码

CF571D Campus

题意

  • 有一个长度为 nn 的序列,初始全为 00。
  • 有两类对下标的集合,初始时每一类各有 nn 个集合,编号为 ii 的集合里有下标 ii。
  • 一共有 mm 个操作,操作有五种:
    1. U x y 将第一类编号为 yy 的集合合并到编号为 xx 的集合里。
    2. M x y 将第二类编号为 yy 的集合合并到编号为 xx 的集合里。
    3. A x 将第一类编号为 xx 的集合中的所有下标在序列中对应的数加上 xx 的集合大小。
    4. Z x 将第二类编号为 xx 的集合中的所有下标在序列中对应的数设为 00。
    5. Q x 询问序列中下标为 xx 的位置上的数。
  • n,m≤5×105n,m \le 5 \times 10^5。

题解

如果我们能够利用 M 和 Z 操作求出对于每个询问的位置上次清零的时刻 tt,那么这个询问的答案就应该是只保留 U 和 A 操作的情况下此时的值减去 tt 时刻的值。

那么我们要解决的问题可以分为两步:

  1. 利用 M 和 Z 操作求出对于每个询问的位置上次清零的时刻 tt。
  2. 利用 U 和 A 操作求出对于每个询问的位置当前和时刻 tt 的值。

将询问离线后,建立 kruskal 重构树,那么这两步就分别相当于在 dfs 序上进行区间赋值和区间加,询问则相当于单点查询,线段树维护即可。

设 n,mn,m 同阶,时间复杂度为 O(nlog⁡n)\mathcal O(n \log n)。

代码

const int N = 5e5 + 7;
int n, m, a[N];
char s[N], c[3];
vector<pi> q[N];
ll ans[N];

struct kruskal0 {
	int f[N*2], l[N*2], r[N*2], num, tot;
	vi e[N*2];
	struct T {
		int l, r, s;
	} t[N*8];
	inline void init() {
		for (int i = 1; i <= n; i++) f[i] = i;
		tot = n;
	}
	int get(int x) {
		return x == f[x] ? x : (f[x] = get(f[x]));
	}
	inline int add(int x, int y) {
		e[++tot].pb(x = get(x)), e[tot].pb(y = get(y));
		return f[x] = f[y] = f[tot] = tot;
	}
	void dfs(int x) {
		l[x] = ++num;
		for (auto y : e[x]) dfs(y);
		r[x] = num;
	}
	void build(int p, int l, int r) {
		t[p].l = l, t[p].r = r;
		if (l == r) return;
		build(ls, l, md), build(rs, md + 1, r);
	}
	inline void prework() {
		for (int i = 1; i <= tot; i++) if (get(i) == i) dfs(i);
		build(1, 1, tot);
	}
	inline void spd(int p) {
		if (t[p].s) t[ls].s = t[rs].s = t[p].s, t[p].s = 0;
	}
	void set(int p, int l, int r, int x) {
		if (t[p].l >= l && t[p].r <= r) return t[p].s = x, void();
		spd(p);
		if (l <= md) set(ls, l, r, x);
		if (r > md) set(rs, l, r, x);
	}
	inline void set(int i) {
		set(1, l[a[i]], r[a[i]], i);
	}
	int asks(int p, int x) {
		if (t[p].l == t[p].r) return t[p].s;
		spd(p);
		return asks(x <= md ? ls : rs, x);
	}
	inline int asks(int i) {
		return asks(1, l[a[i]]);
	}
} t0;

struct kruskal1 {
	int f[N*2], s[N*2], l[N*2], r[N*2], num, tot;
	vi e[N*2];
	struct T {
		int l, r;
		ll a;
	} t[N*8];
	inline void init() {
		for (int i = 1; i <= n; i++) f[i] = i;
		tot = n;
	}
	int get(int x) {
		return x == f[x] ? x : (f[x] = get(f[x]));
	}
	inline int add(int x, int y) {
		e[++tot].pb(x = get(x)), e[tot].pb(y = get(y));
		return f[x] = f[y] = f[tot] = tot;
	}
	void dfs(int x) {
		l[x] = ++num, s[x] = x <= n;
		for (auto y : e[x]) dfs(y), s[x] += s[y];
		r[x] = num;
	}
	void build(int p, int l, int r) {
		t[p].l = l, t[p].r = r;
		if (l == r) return;
		build(ls, l, md), build(rs, md + 1, r);
	}
	inline void prework() {
		for (int i = 1; i <= tot; i++) if (get(i) == i) dfs(i);
		build(1, 1, tot);
	}
	inline void spd(int p) {
		if (t[p].a) t[ls].a += t[p].a, t[rs].a += t[p].a, t[p].a = 0;
	}
	void add(int p, int l, int r, int x) {
		if (t[p].l >= l && t[p].r <= r) return t[p].a += x, void();
		spd(p);
		if (l <= md) add(ls, l, r, x);
		if (r > md) add(rs, l, r, x);
	}
	inline void add(int x) {
		add(1, l[x], r[x], s[x]);
	}
	ll aska(int p, int x) {
		if (t[p].l == t[p].r) return t[p].a;
		spd(p);
		return aska(x <= md ? ls : rs, x);
	}
	inline ll aska(int x) {
		return aska(1, l[x]);
	}
} t1;

int main() {
	rd(n), rd(m), t1.init(), t0.init();
	for (int i = 1, x; i <= m; i++) {
		rds(c, x), s[i] = c[1], rd(a[i]);
		switch (s[i]) {
			case 'U' : rd(x), a[i] = t1.add(a[i], x); break;
			case 'M' : rd(x), a[i] = t0.add(a[i], x); break;
			case 'A' : a[i] = t1.get(a[i]); break;
			case 'Z' : a[i] = t0.get(a[i]); break;
		}
	}
	t1.prework(), t0.prework();
	for (int i = 1; i <= m; i++)
		switch (s[i]) {
			case 'Z' : t0.set(i); break;
			case 'Q' : q[t0.asks(i)].pb(mp(a[i], i)); break;
		}
	for (int i = 1; i <= m; i++)
		switch (s[i]) {
			case 'A' : t1.add(a[i]); break;
			case 'Z' : for (pi o : q[i]) ans[o.se] -= t1.aska(o.fi); break;
			case 'Q' : ans[i] += t1.aska(a[i]); break;
		}
	for (int i = 1; i <= m; i++) if (s[i] == 'Q') print(ans[i]);
	return 0;
}

标签:Kruskal 重构树、并查集、线段树

评论

    填写昵称即可留言。评论经站主审核后公开,请勿提交私人信息。

    正在连接评论服务…