题解 P4219 【[BJOI2014]大融合】
看到很多人用 LCT 水过了此题,本人并没写过 LCT ,所以只好用一种笨办法,但是比 LCT 常数低太多。
对这个森林的操作只有不断地连边,而没有删边,我们不妨看成这本来是一棵树,接着不断有边被“点亮”,就合并了子树。最开始读一遍,把这颗树建出来,再重新扫一遍,连边的时候,用并查集维护每个节点所在树的根。
统计每个节点的子树大小。通过
总复杂度
注:样例代码只有开启
#include <cstdio>
#include <algorithm>
#include <numeric>
using namespace std;
struct edge {
int v;
edge* next;
};
const int N = 100010;
int n;
char opt[N];
int eu[N], ev[N], p[N], f[N], son[N], sum[N], fw[N], ord[N];
int top[N];
edge* g[N];
int find(int x);
void add_edge(int u, int v);
void dfs1(int u);
void dfs2(int u);
void change(int k, int x);
void tchange(int u, int x);
int query(int k);
int low_bit(int k);
int main() {
int q;
scanf("%d%d", &n, &q);
for (int i = 1; i <= q; ++i) {
scanf(" %c%d%d", &opt[i], &eu[i], &ev[i]);
if (opt[i] == 'A') {
add_edge(eu[i], ev[i]);
add_edge(ev[i], eu[i]);
}
}
for (int u = 1; u <= n; ++u)
if (!p[u]) {
p[u] = -1;
dfs1(u);
}
for (int u = 1; u <= n; ++u)
if (p[u] == -1) {
top[u] = u;
dfs2(u);
}
iota(f + 1, f + n + 1, 1);
for (int i = 1; i <= n; ++i) {
tchange(i, 1);
tchange(p[i], -1);
}
for (int i = 1; i <= q; ++i) {
int u = eu[i], v = ev[i];
if (p[u] == v)
swap(u, v);
int sv = query(ord[v]);
if (opt[i] == 'A') {
f[v] = find(u);
tchange(u, sv);
tchange(p[f[u]], -sv);
} else {
int s = query(ord[find(u)]);
printf("%d\n", (s - sv) * sv);
}
}
return 0;
}
void tchange(int u, int x) {
while (u != -1) {
change(ord[top[u]], x);
change(ord[u] + 1, -x);
u = p[top[u]];
}
}
void dfs2(int u) {
static int t;
ord[u] = ++t;
if (!son[u])
return;
top[son[u]] = top[u];
dfs2(son[u]);
for (edge* q = g[u]; q; q = q->next)
if (p[q->v] == u && q->v != son[u]) {
top[q->v] = q->v;
dfs2(q->v);
}
}
int low_bit(int k) {
return k & -k;
}
void change(int k, int x) {
for (; k <= n; k += low_bit(k))
fw[k] += x;
}
int query(int k) {
int ret = 0;
for (; k; k -= low_bit(k))
ret += fw[k];
return ret;
}
void dfs1(int u) {
sum[u] = 1;
for (edge* q = g[u]; q; q = q->next)
if (!p[q->v]) {
p[q->v] = u;
dfs1(q->v);
sum[u] += sum[q->v];
if (sum[son[u]] < sum[q->v])
son[u] = q->v;
}
}
int find(int x) {
return f[x] == x ? x : (f[x] = find(f[x]));
}
void add_edge(int u, int v) {
static edge pool[N * 2];
static edge* p = pool;
p->v = v;
p->next = g[u];
g[u] = p;
++p;
}