题解 [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;
}
posted @   Administrator-09  阅读(2)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· 没有源码,如何修改代码逻辑?
· PowerShell开发游戏 · 打蜜蜂
· 在鹅厂做java开发是什么体验
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战
点击右上角即可分享
微信分享提示