题意
\(n\)个点,维护两个森林,这里\(A,B\)两个森林对应的点都是一样的,相当于对两个森林操作都会影响这\(n\)个点
开始森林里的树都是一个点,\(A,B\)支持合并(但树结构互不影响),\(A\)支持树赋\(0\),\(B\)支持树加值
做法
\(A,B\)分开做,每次合并新建一个虚点,这样相当于把\(n\)个点拍扁了,就比较好维护点集的操作
求出对每次查询最近的一次赋\(0\)操作,然后再在这个区间里算\(B\)修改对该点的贡献
将操作离线下来放在树上就可以做了
有个小\(trick\)就是用树状数组倍增一下求最近的那次赋\(0\)操作
Code(jly)
#include <bits/stdc++.h>
using namespace std;
constexpr int N = 500000;
struct Tree {
int n;
vector<int> parent, lc, rc, id;
vector<vector<int>> mod;
Tree(int n) {
parent.assign(2 * n - 1, -1);
lc.assign(2 * n - 1, -1);
rc.assign(2 * n - 1, -1);
id.resize(n);
iota(id.begin(), id.end(), 0);
mod.resize(2 * n - 1);
}
};
long long fen[N + 1];
void add(int x, int y) {
for (int i = x + 1; i <= N; i += i & -i)
fen[i] += y;
}
long long sum(int x) {
long long res = 0;
for (int i = x; i > 0; i -= i & -i)
res += fen[i];
return res;
}
long long sum(int l, int r) {return sum(r) - sum(l);}
int getLeft(int x) {
int s = sum(x);
x = 0;
for (int i = 1 << 18; i > 0; i /= 2) {
if (x + i <= N && fen[x + i] < s) {
x += i;
s -= fen[x];
}
}
return x;
}
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int n, m;
cin >> n >> m;
Tree t1(n), t2(n);
vector<vector<int>> query(n);
vector<int> lb(m), sz(2 * n - 1, 1);
vector<long long> ans(m, -1);
int c1 = 0, c2 = 0;
for (int i = 0; i < m; ++i) {
char op;
cin >> op;
if (op == 'U') {
int a, b;
cin >> a >> b;
--a;
--b;
int p = n + (c1++);
t1.parent[t1.id[a]] = t1.parent[t1.id[b]] = p;
t1.lc[p] = t1.id[a];
t1.rc[p] = t1.id[b];
t1.id[a] = p;
sz[p] = sz[t1.lc[p]] + sz[t1.rc[p]];
} else if (op == 'M') {
int a, b;
cin >> a >> b;
--a;
--b;
int p = n + (c2++);
t2.parent[t2.id[a]] = t2.parent[t2.id[b]] = p;
t2.lc[p] = t2.id[a];
t2.rc[p] = t2.id[b];
t2.id[a] = p;
} else if (op == 'A') {
int x;
cin >> x;
--x;
t1.mod[t1.id[x]].push_back(i);
} else if (op == 'Z') {
int x;
cin >> x;
--x;
t2.mod[t2.id[x]].push_back(i);
} else {
int x;
cin >> x;
--x;
query[x].push_back(i);
}
}
function<void(int)> dfs1 = [&](int u) {
for (int i : t2.mod[u])
add(i, 1);
if (u < n) {
for (int i : query[u])
lb[i] = getLeft(i);
} else {
dfs1(t2.lc[u]);
dfs1(t2.rc[u]);
}
for (int i : t2.mod[u])
add(i, -1);
};
function<void(int)> dfs2 = [&](int u) {
for (int i : t1.mod[u])
add(i, sz[u]);
if (u < n) {
for (int i : query[u])
ans[i] = sum(lb[i], i);
} else {
dfs2(t1.lc[u]);
dfs2(t1.rc[u]);
}
for (int i : t1.mod[u])
add(i, -sz[u]);
};
for (int i = 0; i < n + c2; ++i)
if (t2.parent[i] == -1)
dfs1(i);
for (int i = 0; i < n + c1; ++i)
if (t1.parent[i] == -1)
dfs2(i);
for (int i = 0; i < m; ++i)
if (ans[i] != -1)
cout << ans[i] << "\n";
return 0;
}