容易发现,这个难啊,要动态维护重心,有一个 (color {black} { ext {n}} color {red} { ext{aive}}) 的想法就是直接 (O (n log^2 n)) 启发式合并,但是我们的 (color {black} { ext {Y}} color {red} { ext {outh518}}) 大佬直接利用LCT爆切。
可以发现的是,如果两个树合并,那么他们的重心必定在原来两个树重心的路径上。那么我们其实可以合并后split一下利用splay来跳,可以快速得到重心的位置,这个复杂度可以做到 (O(n log n))。
/*
Name:
Author: Gensokyo_Alice
Date:
Description:
*/
#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdlib>
#include <cstdio>
#include <vector>
#include <queue>
#include <stack>
#include <cmath>
#include <ctime>
#include <map>
#include <set>
using namespace std;
typedef long long ll;
const ll MAXN = (1LL << 20) + 10, INF = 0x3f3f3f3f3f3f3f3f;
ll N, M, ans, r[MAXN], c[MAXN][2], fa[MAXN], st[MAXN], s[MAXN], si[MAXN], f[MAXN];
void link(ll, ll);
void access(ll);
void split(ll, ll);
void cut(ll, ll);
void makeroot(ll);
ll findroot(ll);
void splay(ll);
void rotate(ll);
ll find_(ll);
ll updata(ll);
void pushup(ll);
void pushr(ll);
void pushdown(ll);
int main() {
scanf("%lld%lld", &N, &M);
for (ll i = 1; i <= N; i++) s[i] = 1, f[i] = i, ans ^= i;
for (ll i = 1, x, y; i <= M; i++) {
char s[10];
scanf("%s", s+1);
if (s[1] == 'A') {
scanf("%lld%lld", &x, &y);
link(x, y);
x = find_(x), y = find_(y);
split(x, y);
ll z = updata(y);
ans = ans ^ x ^ y ^ z;
f[x] = f[y] = f[z] = z;
} else if (s[1] == 'Q') {
scanf("%lld", &x);
printf("%lld
", find_(x));
} else if (s[1] == 'X') printf("%lld
", ans);
}
return 0;
}
void access(ll x) {for (ll y = 0; x; y = x, x = fa[x]) splay(x), si[x] += s[c[x][1]], si[x] -= s[c[x][1] = y], pushup(x);}
void makeroot(ll x) {access(x); splay(x); pushr(x);}
void link(ll x, ll y) {split(x, y); if (findroot(y) != x) si[fa[x] = y] += s[x];}
void split(ll x, ll y) {makeroot(x); access(y); splay(y);}
void cut(ll x, ll y) {split(x, y); if (findroot(y) != x || fa[y] != x || c[y][0]) return; fa[y] = c[x][1] = 0;}
void pushr(ll x) {swap(c[x][0], c[x][1]); r[x] ^= 1;}
void pushup(ll x) {s[x] = s[c[x][0]] + s[c[x][1]] + si[x] + 1;}
void pushdown(ll x) {if (r[x]) {if (c[x][0]) pushr(c[x][0]); if (c[x][1]) pushr(c[x][1]);} r[x] = 0;}
bool nroot(ll x) {return c[fa[x]][0] == x || c[fa[x]][1] == x;}
ll findroot(ll x) {access(x); splay(x); while (c[x][0]) x = c[x][0]; return x;}
void splay(ll x) {
ll y = x, z = 0; st[++z] = y;
while (nroot(y)) st[++z] = (y = fa[y]); while (z) pushdown(st[z--]);
while (nroot(x)) {
y = fa[x], z = fa[y];
if (nroot(y)) rotate(((c[y][0] == x) ^ (c[z][0] == y)) ? x : y);
rotate(x);
}
pushup(x);
}
void rotate(ll x) {
ll y = fa[x], z = fa[y], k = c[y][1] == x, w = c[x][!k];
if (nroot(y)) c[z][c[z][1] == y] = x; c[x][!k] = y; c[y][k] = w;
if (w) fa[w] = y; fa[y] = x; fa[x] = z;
pushup(y);
}
ll find_(ll x) {return f[x] == x ? x : f[x] = find_(f[x]);}
ll updata(ll node) {
ll l, r, ji = s[node] & 1, sum = s[node] >> 1, lsum = 0, rsum = 0, nowl, nowr, tar = INF;
while (node) {
pushdown(node);
nowl = s[l = c[node][0]] + lsum, nowr = s[r = c[node][1]] + rsum;
if (nowl <= sum && nowr <= sum) {
if (ji & 1) {tar = node; break;}
else if (tar > node) tar = node;
}
if (nowl < nowr) lsum += s[l] + si[node] + 1, node = r;
else rsum += s[r] + si[node] + 1, node = l;
}
splay(tar);
return tar;
}