洛谷P4219 大融合

时间:2023-03-09 23:02:58
洛谷P4219 大融合

LCT新姿势:维护子树信息。

不能带修,子树修改就要toptree了...

题意:动态加边,求子树大小。

解:

维护子树信息只要额外维护虚边连的儿子的信息即可。这里把siz的定义变成子树大小。

哪里会修改虚边呢?link和access。把这两个函数改一改就行了。

注意这里link的时候x和y都要make_root,因为修改只能修改根。

 #include <cstdio>
#include <algorithm> typedef long long LL;
const int N = ; int fa[N], s[N][], sum[N], val[N], S[N], Sp;
bool rev[N]; inline bool no_root(int x) {
return (s[fa[x]][] == x) || (s[fa[x]][] == x);
} inline void pushup(int x) {
sum[x] = sum[s[x][]] + sum[s[x][]] + val[x];
return;
} inline void pushdown(int x) {
if(rev[x]) {
if(s[x][]) {
rev[s[x][]] ^= ;
}
if(s[x][]) {
rev[s[x][]] ^= ;
}
std::swap(s[x][], s[x][]);
rev[x] = ;
}
return;
} inline void rotate(int x) {
int y = fa[x];
int z = fa[y];
bool f = (s[y][] == x); fa[x] = z;
if(no_root(y)) {
s[z][s[z][] == y] = x;
}
s[y][f] = s[x][!f];
if(s[x][!f]) {
fa[s[x][!f]] = y;
}
s[x][!f] = y;
fa[y] = x; pushup(y);
pushup(x);
return;
} inline void splay(int x) {
int y = x;
S[++Sp] = y;
while(no_root(y)) {
y = fa[y];
S[++Sp] = y;
}
while(Sp) {
pushdown(S[Sp]);
Sp--;
} y = fa[x];
int z = fa[y];
while(no_root(x)) {
if(no_root(y)) {
(s[z][] == y) ^ (s[y][] == x) ?
rotate(x) : rotate(y);
}
rotate(x);
y = fa[x];
z = fa[y];
}
return;
} inline void access(int x) {
int y = ;
while(x) {
splay(x);
val[x] += sum[s[x][]] - sum[y];
s[x][] = y;
pushup(x);
y = x;
x = fa[x];
}
return;
} inline void make_root(int x) {
access(x);
splay(x);
rev[x] = ;
return;
} inline void link(int x, int y) {
make_root(x);
make_root(y);
fa[x] = y;
val[y] += sum[x];
sum[y] += sum[x];
return;
} inline int ask(int x, int r) {
make_root(x);
access(r);
splay(r);
return sum[x];
} char str[]; int main() {
int n, q;
scanf("%d%d", &n, &q);
for(int i = ; i <= n; i++) {
val[i] = ;
}
for(int i = , x, y; i <= q; i++) {
scanf("%s%d%d", str, &x, &y);
if(str[] == 'A') {
link(x, y);
}
else {
int t = ask(x, y);
int tt = ask(y, x);
printf("%lld\n", 1ll * t * tt);
}
} return ;
}

AC代码