P4219 [BJOI2014]大融合【LCT】维护子树信息

6 篇文章 0 订阅
1 篇文章 0 订阅

传送门

分析

维护子树信息

这里用个 s z 2 sz2 sz2 维护虚子树节点数量

也就是非实子树的数量

需要更新 s z 2 sz2 sz2的地方在, a c c e s s access access 过程中, t r [ x ] . s o n [ 1 ] = p tr[x].son[1]=p tr[x].son[1]=p会修改,此时需要把原来的实边的子树加到虚子树中,更新实子树的答案

同时在 l i n k link link的过程中,存在 t r [ x ] . f a = y tr[x].fa = y tr[x].fa=y,此时对 y y y进行更新,需要把 y y y s p l a y splay splay到根后进行操作(此处存在坑点)

代码

//P4219 
/*
  @Author: YooQ
*/
#include <bits/stdc++.h>
using namespace std;
#define sc scanf
#define pr printf
#define ll long long
#define int long long
#define FILE_OUT freopen("out", "w", stdout);
#define FILE_IN freopen("P4219_2.in", "r", stdin);
#define debug(x) cout << #x << ": " << x << "\n";
#define max3(a, b, c) max(a, max(b, c))
#define min3(a, b, c) min(a, min(b, c))
#define AC 0
#define WA 1
#define INF 0x3f3f3f3f
const ll MAX_N = 1e6+5;
const ll MOD = 1e9+7;
int N, M, K;

struct Tr {
	int fa, rev, sz, sz2;
	int son[2];
}tr[MAX_N];

void push_up(int rt) {
	tr[rt].sz = tr[tr[rt].son[0]].sz + tr[tr[rt].son[1]].sz + tr[rt].sz2 + 1;
}

void push_rev(int rt) {
	swap(tr[rt].son[0], tr[rt].son[1]);
	tr[rt].rev ^= 1;
}

void push_down(int rt) {
	if (!tr[rt].rev) return;
	int ls = tr[rt].son[0];
	int rs = tr[rt].son[1];
	
	if (ls) push_rev(ls);
	if (rs) push_rev(rs);
	tr[rt].rev ^= 1;
}

bool nroot(int x) {
	return tr[tr[x].fa].son[0] == x || tr[tr[x].fa].son[1] == x;
}

bool which(int x) {
	return tr[tr[x].fa].son[1] == x;
}

void rotate(int x) {
	int p = tr[x].fa;
	int q = tr[p].fa;
	int side = which(x);
	
	if (nroot(p)) tr[q].son[which(p)] = x;
	tr[tr[p].son[side] = tr[x].son[side^1]].fa = p;
	tr[tr[x].son[side^1] = p].fa = x;
	tr[x].fa = q;
	
	push_up(p); push_up(x);
}

void flush(int x) {
	if (nroot(x)) flush(tr[x].fa);
	push_down(x);
}

void splay(int x) {
	flush(x);
	
	for (int p; nroot(x); rotate(x)) {
		if (nroot(p = tr[x].fa)) rotate(which(x) == which(p) ? p : x);
	}
}

void access(int x) {
	for (int p = 0; x; x = tr[p = x].fa) {
		splay(x);
		tr[x].sz2 += tr[tr[x].son[1]].sz;
		tr[x].sz2 -= tr[tr[x].son[1] = p].sz;
		push_up(x);
	}
}

int findroot(int x) {
	access(x); splay(x);
	while (tr[x].son[0]) {
		push_down(x);
		x = tr[x].son[0];
	}
	splay(x);
	return x;
}

void mkroot(int x) {
	access(x); splay(x);
	push_rev(x);
}

void split(int x, int y) {
	mkroot(x); access(y);
	splay(y);
}

void link(int x, int y) {
	mkroot(x);
	if (findroot(y) == x) return;
	splay(y);
	tr[tr[x].fa = y].sz2 += tr[x].sz;
	push_up(y);
}

void cut(int x, int y) {
	mkroot(x);
	if (findroot(y) != x || tr[y].fa != x || tr[y].son[0]) return;
	tr[y].fa = tr[x].son[1] = 0;
	push_up(x);
}

void solve() {
	sc("%lld%lld", &N, &M);
	char opt[5];
	int x, y;
	
	for (int i = 1; i <= N; ++i) {
		tr[i].sz = 1;
	}
	
	int ans = 0;
	for (int i = 1; i <= M; ++i) {
		sc("%s", opt);
		sc("%lld%lld", &x, &y);
		if (*opt == 'A') {
			link(x, y);
		} else {
//			split(x, y);
//			pr("%lld\n", (tr[x].sz2 + 1) * (tr[y].sz2 + 1));
			cut(x, y);
			mkroot(x);
			ans = tr[x].sz;
			mkroot(y);
			ans = tr[y].sz * ans;
			link(x, y);
			pr("%lld\n", ans);
		}
	}
}

signed main() {
	#ifndef ONLINE_JUDGE
	FILE_IN
	FILE_OUT
	#endif
	int T = 1;//cin >> T;
	while (T--) solve();

	return AC;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Hexrt

客官,请不要给我小费!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值