题解 [BJOI2014] 大融合
本来是个 LCT 维护虚子树的板子
但是我调了 150min 所以来记录一下易错点
首先只有虚实边发生变化的操作需要修改 vsiz
也即只有 access 和 link 操作需要修改 vsiz
access 还好说,删去变成实边的,加上变为虚边的即可
但这个 link 并不是简单加减一下就行了
发现若将 x 加为 y 的虚儿子,若 y 不是所在辅助树的跟则其祖先的 siz 会错掉
所以 x 和 y 都要 makerot
void link(int x, int y) {
if (findrot(x)==findrot(y)) return ;
makerot(x); makerot(y);
splay(x); vsiz(y)+=siz(x); fa(x)=y; pushup(y);
}
点击查看代码
#include <bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
#define N 100010
#define ll long long
//#define int long long
int n, m;
char op[N];
int son[N][2], fa[N], siz[N], vsiz[N], rev[N];
#define son(a, b) son[a][b]
#define fa(a) fa[a]
#define siz(a) siz[a]
#define rev(a) rev[a]
#define vsiz(a) vsiz[a]
#define loc(a) (son(fa(a), 1)==a)
#define isrot(a) (son(fa(a), 0)!=a && son(fa(a), 1)!=a)
#define pushup(a) siz(a)=siz(son(a, 0))+siz(son(a, 1))+vsiz(a)+1
void spread(int a) {
if (!rev(a)) return ;
if (son(a, 0)) swap(son(son(a, 0), 0), son(son(a, 0), 1)), rev(son(a, 0))^=1;
if (son(a, 1)) swap(son(son(a, 1), 0), son(son(a, 1), 1)), rev(son(a, 1))^=1;
rev(a)=0;
}
void ror(int x) {
int y=fa(x), z=fa(y), k=loc(x);
if (!isrot(y)) son(z, loc(y))=x; fa(x)=z;
son(y, k)=son(x, k^1); fa(son(x, k^1))=y;
son(x, k^1)=y; fa(y)=x;
pushup(y); pushup(x);
}
void upd(int x) {if (!isrot(x)) upd(fa(x)); spread(x);}
void splay(int x) {
// cout<<"splay: "<<x<<endl;
upd(x);
for (int f; f=fa(x),!isrot(x); ror(x))
if (!isrot(f)) loc(x)^loc(f)?ror(x):ror(f);
}
int access(int x) {
// cout<<"access: "<<x<<endl;
int lst;
for (lst=0; x; lst=x,x=fa(x))
splay(x), vsiz(x)+=siz(son(x, 1))-siz(lst), son(x, 1)=lst, pushup(x);
return lst;
}
void makerot(int x) {
access(x); splay(x);
swap(son(x, 0), son(x, 1));
rev(x)^=1;
}
int findrot(int x) {
x=access(x); spread(x);
while (son(x, 0)) x=son(x, 0), spread(x);
splay(x);
return x;
}
void split(int x, int y) {makerot(x); access(y); splay(y);}
void link(int x, int y) {
if (findrot(x)==findrot(y)) return ;
makerot(x); makerot(y);
splay(x); vsiz(y)+=siz(x); fa(x)=y; pushup(y);
}
void cut(int x, int y) {
makerot(x);
if (findrot(y)!=x||son(y, 0)||fa(y)!=x) return ;
split(x, y); fa(x)=son(y, 0)=0; pushup(y);
}
signed main()
{
scanf("%d%d", &n, &m);
for (int i=1; i<=n; ++i) siz(i)=1;
for (int i=1,x,y; i<=m; ++i) {
cout<<"i: "<<i<<endl;
scanf("%s%d%d", op, &x, &y);
if (*op=='A') link(x, y);
else {
cut(x, y);
makerot(x); makerot(y);
printf("%lld\n", 1ll*siz(x)*siz(y));
link(x, y);
// cout<<"siz: "<<siz(x)<<' '<<siz(y)<<endl;
}
// cout<<"fa: "; for (int i=1; i<=n; ++i) cout<<fa(i)<<' '; cout<<endl;
// cout<<"son_0: "; for (int i=1; i<=n; ++i) cout<<son(i, 0)<<' '; cout<<endl;
// cout<<"son_1: "; for (int i=1; i<=n; ++i) cout<<son(i, 1)<<' '; cout<<endl;
// cout<<"siz: "; for (int i=1; i<=n; ++i) cout<<siz(i)<<' '; cout<<endl;
// cout<<"vsiz: "; for (int i=1; i<=n; ++i) cout<<vsiz(i)<<' '; cout<<endl;
}
return 0;
}
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· 没有源码,如何修改代码逻辑?
· PowerShell开发游戏 · 打蜜蜂
· 在鹅厂做java开发是什么体验
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战