ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

动态树之 Link Cut Tree 学习笔记

2022-07-20 12:05:53  阅读:203  来源: 互联网

标签:LCT Cut 标记 Tree 三叉神经 Link 维护 节点 分量


LCT 题单做题记录

一、维护链信息

二、动态维护连通性&双联通分量

  • P2542 [AHOI2005] 航线规划:离线倒序处理操作。对于连接后成环的两个节点,把其中一个 \(makeroot()\),然后缩点——每个其子树内节点的并查集父亲赋为此点编号,此点与儿子断开连接。此时这个点代表着它和它儿子们组成的一个点双连通分量(成环)。那么若查询两个节点间的“关键航线”,就是 \(split()\) 它们两个各自的并查集祖先。

  • 【DSY1664/BZOJ2959】长跑:题目中虽然说“没有给定每条单向边的方向,自行选择边的方向”,但是我们可以发现对于一个强连通分量,我们肯定都会走一遍,所以又变成了和上面航线规划一样的缩点了,每次查询还是 \(split()\) 它俩的代表节点,然后直接输出分裂出的子树的总和即可。

三、维护子树信息

  • P4219 [BJOI2014]大融合:其实一眼就能看出大概思路,关键在于维护每个节点的 \(exsize\),即和该节点以虚边相连的儿子数,具体只要在 \(access\) 和 \(link\) 中多一步更新 \(exsize\) 即可。

LCT 板子代码

#include<bits/stdc++.h>
using namespace std;

#define rep(i, a, b) for(register int i = a; i <= b; ++i)
#define ls t[x].ch[0]
#define rs t[x].ch[1]
const int maxn = 3e5 + 5;
int n, m;
struct node{
	int f, ch[2], sum, val;
	bool rev;
}t[maxn];

inline bool nrt(int p)
{
	int x = t[p].f;
	return (ls == p or rs == p);
}

inline void up(int x) {t[x].sum = t[ls].sum ^ t[rs].sum ^ t[x].val;}

inline void rv(int x) {swap(ls, rs); t[x].rev ^= 1;}

inline void dw(int x)
{
	if(!t[x].rev) return;
	if(ls) rv(ls); if(rs) rv(rs);
	t[x].rev = 0;
}

inline void rotate(int x)
{
	int y = t[x].f, z = t[y].f;
	int kx = (t[y].ch[1] == x), ky = (t[z].ch[1] == y), w = t[x].ch[!kx];
	if(nrt(y)) t[z].ch[ky] = x;
	t[x].ch[!kx] = y, t[y].ch[kx] = w;
	if(w) t[w].f = y;
	t[y].f = x, t[x].f = z;
	up(y), up(x);
}

inline void pushall(int x) {if(nrt(x)) pushall(t[x].f); dw(x);}

inline void splay(int x)
{
	pushall(x);
	while(nrt(x))
	{
		int y = t[x].f, z = t[y].f;
		if(nrt(y)) rotate((t[z].ch[1] == y) ^ (t[y].ch[1] == x) ? x : y);
		rotate(x);
	}
	up(x);
}

inline void access(int x)
{
	for(register int lst = 0; x; x = t[lst = x].f)
		splay(x), rs = lst, up(x);
}

inline void mkrt(int x) {access(x), splay(x), rv(x);}

inline int fndrt(int x)
{
	access(x), splay(x);
	while(ls) dw(x), x = ls;
	splay(x); return x;
}

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

inline void link(int x, int y) {mkrt(x); if(fndrt(y) != x) t[x].f = y;}

inline void cut(int x, int y)
{
	split(x, y);
	if(fndrt(y) == x and t[y].f == x and !t[y].ch[0])
		t[y].f = t[x].ch[1] = 0, up(x);
}

int main()
{
	scanf("%d%d", &n, &m);
	rep(i, 1, n) scanf("%d", &t[i].val);
	rep(i, 1, m)
	{
		int opt, x, y;
		scanf("%d%d%d", &opt, &x, &y);
		if(!opt) split(x, y), printf("%d\n", t[y].sum);
		if(opt == 1) link(x, y);
		if(opt == 2) cut(x, y);
		if(opt == 3) splay(x), t[x].val = y;
	}
	return 0;
}

标签:LCT,Cut,标记,Tree,三叉神经,Link,维护,节点,分量
来源: https://www.cnblogs.com/gsn531/p/16497413.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有