为什么在 merge 中,连接两点时更新 fa 数组是错的?
具体而言,将下述代码 77 行、83 行注释去掉,去掉 push_up
中维护的 fa,是错的。
但是不是 fa 被修改意味着儿子被修改,所以在修改儿子的时候修改父亲不对呢?
#include <bits/stdc++.h>
#define ls(x) tr[x].ls
#define rs(x) tr[x].rs
using namespace std;
typedef pair<int, int> pii;
const int N = 2e5 + 10;
struct node {
int ls, rs;
int val;
int sz, s;
char ch;
bool tag;
};
node tr[N];
int root, idx;
bool vis[N];
int mp[N], fa[N];
int make_node(char ch) {
tr[++idx] = {0, 0, -rand(), 1, (1 << (ch - 'a')), ch, 0};
return idx;
}
void push_up(int p) {
if (!p)
return;
if (ls(p))
fa[ls(p)] = p;
if (rs(p))
fa[rs(p)] = p;
tr[p].sz = tr[ls(p)].sz + tr[rs(p)].sz + 1;
tr[p].s = tr[ls(p)].s | tr[rs(p)].s | (1 << (tr[p].ch - 'a'));
}
void eval(node &t) { t.tag = t.tag ^ 1; }
void push_down(int p) {
if (!p)
return;
if (tr[p].tag) {
eval(tr[ls(p)]);
eval(tr[rs(p)]);
swap(ls(p), rs(p));
tr[p].tag = 0;
}
}
tuple<int, int, int> split_by_rank(int p, int rank) {
if (!p)
return {0, 0, 0};
push_down(p);
if (rank <= tr[ls(p)].sz) {
int l, mid, r;
tie(l, mid, r) = split_by_rank(ls(p), rank);
ls(p) = r;
push_up(p);
return {l, mid, p};
} else if (rank <= tr[ls(p)].sz + 1) {
int l = ls(p), r = rs(p);
ls(p) = rs(p) = 0;
return {l, p, r};
} else {
int l, mid, r;
tie(l, mid, r) = split_by_rank(rs(p), rank - tr[ls(p)].sz - 1);
rs(p) = l;
push_up(p);
return {p, mid, r};
}
}
int merge(int u, int v) {
push_down(u), push_down(v);
push_up(u), push_up(v);
if (!u && !v)
return 0;
if (u && !v)
return u;
if (!u && v)
return v;
if (tr[u].val < tr[v].val) {
int now = merge(rs(u), v);
rs(u) = now;
// fa[now] = u;
push_up(u);
return u;
} else {
int now = merge(u, ls(v));
ls(v) = now;
// fa[now] = v;
push_up(v);
return v;
}
}
int build(int l, int r, string &s) {
if (l > r)
return 0;
int mid = l + r >> 1;
int now = make_node(s[mid]);
mp[mid] = now;
int res1 = build(l, mid - 1, s), res2 = build(mid + 1, r, s);
ls(now) = res1, fa[res1] = now;
rs(now) = res2, fa[res2] = now;
push_up(now);
return now;
}
void insert(int x, char ch) {
int l, mid, r;
tie(l, mid, r) = split_by_rank(root, x);
int a, b, c;
tie(a, b, c) = split_by_rank(mid, 1);
c = make_node(ch);
mid = merge(merge(a, b), c);
root = merge(merge(l, mid), r);
}
void remove(int x) {
int l, mid, r;
tie(l, mid, r) = split_by_rank(root, x);
vis[mid] = 1;
mid = 0;
root = merge(merge(l, mid), r);
}
void rev(int x, int y) {
int l, r, mid;
tie(l, mid, r) = split_by_rank(root, x - 1);
int a, b, c;
tie(a, b, c) = split_by_rank(r, y - x + 2);
eval(tr[a]);
r = merge(merge(a, b), c);
root = merge(merge(l, mid), r);
}
char get_rank(int x) {
int l, mid, r;
tie(l, mid, r) = split_by_rank(root, x);
char res = tr[mid].ch;
root = merge(merge(l, mid), r);
return res;
}
int calc_rank(int p) {
stack<int> q;
int now = p;
while (now != root) {
q.push(now);
now = fa[now];
}
q.push(root);
while (q.size()) {
auto now = q.top();
q.pop();
push_down(now);
}
now = p;
int sz = tr[ls(p)].sz + 1;
while (now != root) {
int cur = fa[now];
if (rs(cur) == now) {
sz += tr[ls(cur)].sz + 1;
}
now = cur;
}
return sz;
}
int get_num(int x, int y) {
int l, r, mid;
tie(l, mid, r) = split_by_rank(root, x - 1);
int a, b, c;
tie(a, b, c) = split_by_rank(r, y - x + 2);
int cnt = 0;
for (int i = 0; i < 26; i++) {
if ((tr[a].s >> i) & 1)
cnt++;
}
r = merge(merge(a, b), c);
root = merge(merge(l, mid), r);
return cnt;
}
void solve() {
int n, m;
cin >> n >> m;
string s;
cin >> s;
s = " " + s;
root = build(1, n, s);
while (m--) {
char op;
cin >> op;
if (op == 'I') {
int x;
char c;
cin >> x >> c;
insert(x, c);
} else if (op == 'D') {
int x;
cin >> x;
remove(x);
} else if (op == 'R') {
int x, y;
cin >> x >> y;
rev(x, y);
} else if (op == 'P') {
int x;
cin >> x;
if (vis[mp[x]])
cout << "0\n";
else {
cout << calc_rank(mp[x]) << '\n';
}
} else if (op == 'T') {
int x;
cin >> x;
cout << get_rank(x) << '\n';
} else {
int x, y;
cin >> x >> y;
cout << get_num(x, y) << '\n';
}
}
}
signed main() {
srand(unsigned(time(0)));
ios::sync_with_stdio(0);
cin.tie(0);
int t = 1;
// cin >> t;
while (t--) {
solve();
}
return 0;
}