动态树之link-cut tree

说好的专题。。。

lct的一些概念看论文 杨哲《QTREE解法的一些研究》 简单易懂。

首先不要把lct想象得很难,其实很水的。lct就是很多splay树维护的树。。。

lct的access操作就是在原树中拓展一条点到根的类二叉树出来(用splay来维护)

这里,splay树是按深度作为关键字的,当然,在无向图中(无环)可以任意指定一个点为根,这点要切记(因为在这里操作时,有些操作需要换根,所以一定要理解)

link操作就是将点作为这颗类二叉树的根,然后合并

cut操作就是将点作为这颗二叉树的根,然后在拓展一条另一个点的splay路径(此时这两个点一定要有边连接,这样使得拓展上来的根一定在另一个点拓展上来的splay树的左子树上,因为他们有边连接),将左子树的父亲设为0,并且去掉左子树

getroot操作就是将点拓展了splay后,并且将它伸展到根,此时,最小的子树(深度最浅,即最左的子树)就是这颗splay的根

makeroot操作就是将点拓展为现在所在的树的根,即换根,伸展到根后只需要将左右子树反向,就是将深度换了(根据splay有良好的下放操作,我们将翻转用标记来翻转,使得时间复杂度减小)

额,我自己都觉得说得不好 。。囧

说些注意的地方吧:

  1. 在维护splay树时,当x为这棵树的根时,并不意味着它没有父亲,只是他的父亲没有这个孩子(这点一定要理解!!),因为我们维护的是一棵多叉树,但是我们拓展的是二叉树,所以,你懂的。怎么修改呢,在原来splay操作的判null的地方都用现在的特判。
  2. 在旋转时,还需要判断父亲的父亲是否为上边所说的那样,如果是,就不要更新他,因为这两个点不在一颗splay上。
  3. splay操作时,下放标记我们要用一个栈到达他的根往下放标记。
  4. 不要把splay和原树搞混。
  5. 不要认为只有一颗splay树。
  6. 不要认为理所当然,,,在思考的时候好好思考。

好了,我认为差不多了。。

一些题我之前也发了博文,我现在再放出来。。

【BZOJ】2002: [Hnoi2010]Bounce 弹飞绵羊

#include <cstdio>
#define read(x) x=getint()

using namespace std;
inline int getint() { char c; int ret=0; for(c=getchar(); c<‘0‘ || c>‘9‘; c=getchar()); for(; c>=‘0‘ && c<=‘9‘; c=getchar()) ret=ret*10+c-‘0‘; return ret; }

const int N=200005;
struct node* null;
struct node {
	node *f, *ch[2];
	int s;
	void pushup() { s=1+ch[0]->s+ch[1]->s; }
	bool d() { return f->ch[1]==this; }
	void setc(node* c, bool d) { ch[d]=c; c->f=this; }
	bool check() { return  f==null || (f->ch[0]!=this && f->ch[1]!=this); } //check操作是lct特地的,因为为了省空间,我们不开n颗splay,只用节点关联就行了,这样就无法避免父亲没有这个孩子的情况。所以还要特判
}*nd[N];

void rot(node* r) {
	node* f=r->f; bool d=r->d();
	if(f->check()) r->f=f->f;
	else f->f->setc(r, f->d()); //这里一定要这样写,不然会让null的孩子改变,这样在splay的循环就会死循环T_T
	f->setc(r->ch[!d], d);
	r->setc(f, !d);
	f->pushup();
}

inline void splay(node* r) {
	while(!r->check())
		if(r->f->check()) rot(r);
		else r->d()==r->f->d()?(rot(r->f), rot(r)):(rot(r), rot(r));
	r->pushup();
}

inline void access(node* f) {
	for(node* c=null; f!=null; f=f->f) {
		splay(f);
		f->setc(c, 1);
		f->pushup();
		c=f;
	}
}

inline void link(node* c, node* f) {
	access(c); splay(c);
	c->ch[0]->f=null; c->ch[0]=null; c->f=f; c->pushup();
}

inline void init() {
	null=new node; null->s=0; null->f=null->ch[0]=null->ch[1]=null;
}

int main() {
	init();
	int n, t; read(n);
	for(int i=0; i<n; ++i) { nd[i]=new node; nd[i]->s=1; nd[i]->ch[0]=nd[i]->ch[1]=nd[i]->f=null; }
	for(int i=0; i<n; ++i) {
		read(t);
		if(i+t<n) nd[i]->f=nd[i+t];
	}
	int m, a, b, c; read(m);
	for(int i=0; i<m; ++i) {
		read(a); read(b);
		if(a==1) {
			access(nd[b]);
			splay(nd[b]);
			printf("%d\n", nd[b]->s);
		}
		else {
			read(c);
			if(b+c<n) link(nd[b], nd[b+c]);
			else link(nd[b], null);
		}
	}
	return 0;
}

【BZOJ】1036: [ZJOI2008]树的统计Count

#include <cstdio>
#include <iostream>
using namespace std;
#define dbg(x) cout << #x << "=" << x << endl
#define read(x) x=getint()
#define print(x) printf("%d", x)
#define max(a,b) ((a)>(b)?(a):(b))

const int oo=~0u>>1;
inline int getint() { char c; int ret=0, k=1; for(c=getchar(); c<‘0‘ || c>‘9‘; c=getchar()) if(c==‘-‘) k=-1; for(; c>=‘0‘&&c<=‘9‘; c=getchar()) ret=ret*10+c-‘0‘; return k*ret; }
const int N=30010, M=100005;
int ihead[N], inext[M], to[M], cnt, q[N], front, tail, n, m;
bool vis[N];

struct node* null;
struct node {
	node* fa, *ch[2];
	int w, sum, mx;
	bool d() { return fa->ch[1]==this; }
	bool check() { return fa->ch[0]!=this && fa->ch[1]!=this; }
	void setc(node* c, bool d) { ch[d]=c; c->fa=this; }
	void pushup() {
		sum=w+ch[0]->sum+ch[1]->sum;
		mx=max(w, max(ch[0]->mx, ch[1]->mx));
	}
}*nd[N];

inline void rot(node* r) {
	node* fa=r->fa; bool d=r->d();
	if(fa->check()) r->fa=fa->fa;
	else fa->fa->setc(r, fa->d());
	fa->setc(r->ch[!d], d);
	r->setc(fa, !d);
	fa->pushup();
}

inline void splay(node* r) {
	while(!r->check())
		if(r->fa->check()) rot(r);
		else r->d()==r->fa->d()?(rot(r->fa), rot(r)):(rot(r), rot(r));
	r->pushup();
}

inline node* access(node* fa) {
	node* c=null;
	for(; fa!=null; c=fa, fa=fa->fa) {
		splay(fa);
		fa->setc(c, 1);
		fa->pushup();
	}
	return c;
}

inline void bfs() {
	vis[1]=1; int u, v, i;
	front=tail=0; q[tail++]=1;
	while(front!=tail) {
		u=q[front++];
		for(i=ihead[u]; i; i=inext[i]) if(!vis[v=to[i]]) {
			vis[v]=1;
			nd[v]->fa=nd[u];
			q[tail++]=v;
		}
	}
}

inline void add(const int &u, const int &v) {
	inext[++cnt]=ihead[u]; ihead[u]=cnt; to[cnt]=v;
	inext[++cnt]=ihead[v]; ihead[v]=cnt; to[cnt]=u;
}

int main() {
	null=new node; null->fa=null->ch[0]=null->ch[1]=null; null->w=null->sum=0; null->mx=oo+1;
	read(n);
	int u, v, t;
	for(int i=1; i<n; ++i) {
		read(u); read(v);
		add(u, v);
	}
	int w;
	for(int i=1; i<=n; ++i) {
		nd[i]=new node;
		read(w);
		nd[i]->w=w;
		nd[i]->ch[0]=nd[i]->ch[1]=nd[i]->fa=null;
	}
	bfs();
	char c[10];
	node* lca=null;
	read(m);
	int ans;
	for(int i=0; i<m; ++i) {
		scanf("%s", c);
		if(c[0]==‘C‘) {
			read(u); read(t);
			splay(nd[u]);
			nd[u]->w=t;
			nd[u]->pushup();
		}
		else if(c[0]==‘Q‘) {
			read(u); read(v);
			access(nd[u]);
			lca=access(nd[v]);
			splay(nd[u]);
			if(nd[u]==lca) {
				if(c[1]==‘M‘) ans=max(lca->w, lca->ch[1]->mx);
				else ans=lca->w + lca->ch[1]->sum;
			}
			else {
				if(c[1]==‘M‘) ans=max(max(lca->w, nd[u]->mx), lca->ch[1]->mx);
				else ans=lca->w + lca->ch[1]->sum + nd[u]->sum;
			}
			printf("%d\n", ans);
		}
	}
	return 0;
}

【BZOJ】2049: [Sdoi2008]Cave 洞穴勘测

#include <cstdio>
#include <cstring>
#include <string>
#include <iostream>
#include <cmath>
#include <algorithm>
using namespace std;
#define rep(i, n) for(int i=0; i<(n); ++i)
#define for1(i,a,n) for(int i=(a);i<=(n);++i)
#define for2(i,a,n) for(int i=(a);i<(n);++i)
#define for3(i,a,n) for(int i=(a);i>=(n);--i)
#define for4(i,a,n) for(int i=(a);i>(n);--i)
#define CC(i,a) memset(i,a,sizeof(i))
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
#define read(a) a=getnum()
#define print(a) printf("%d", a)
#define dbg(x) cout << #x << "=" << x << endl;
#define dbgarr(a, n) for1(i, 0, n) cout << a[i] << " "; cout << endl

inline int getnum() { int ret=0, k=1; char c; for(c=getchar(); c<‘0‘ || c>‘9‘; c=getchar()) if(c==‘-‘) k=-1; for(; c>=‘0‘ && c<=‘9‘; c=getchar()) ret=ret*10+c-‘0‘; return ret*k; }

const int N=10005;
int n, m;

struct node* null;
struct node {
	node* ch[2], *fa;
	bool rev;
	bool d() const { return fa->ch[1]==this; }
	void setc(node* c, bool d) { ch[d]=c; c->fa=this; }
	bool check() const { return fa->ch[0]!=this && fa->ch[1]!=this; }
	void pushdown() {
		if(rev) {
			ch[0]->rev^=true;
			ch[1]->rev^=true;
			swap(ch[0], ch[1]);
			rev=false;
		}
	}
}*nd[N];

inline void rot(node* r) {
	node* fa=r->fa; bool d=r->d();
	fa->pushdown(); r->pushdown();
	if(fa->check()) r->fa=fa->fa;
	else fa->fa->setc(r, fa->d());
	fa->setc(r->ch[!d], d);
	r->setc(fa, !d);
}

void fix(node* x) {
	if(!x->check()) fix(x->fa);
	x->pushdown();
}

inline void splay(node* r) {
	fix(r);
	while(!r->check())
		if(r->fa->check()) rot(r);
		else r->d()==r->fa->d()?(rot(r->fa), rot(r)):(rot(r), rot(r));
}

inline node* access(node* x) {
	node* y=null;
	for(; x!=null; y=x, x=x->fa) {
		splay(x);
		x->ch[1]=y;
	}
	return y;
}

inline void mkroot(node* x) {
	access(x)->rev^=true; splay(x);
}

inline void link(node* x, node* y) {
	mkroot(x); x->fa=y;
}

inline void cut(node* x, node* y) {
	mkroot(x);
	access(y); splay(y);
	y->ch[0]->fa=null; y->ch[0]=null;
}

inline node* findrt(node* x) {
	access(x); splay(x);
	while(x->ch[0]!=null) x=x->ch[0];
	return x;
}

int main() {
	read(n); read(m);
	null=new node; null->fa=null->ch[0]=null->ch[1]=null; null->rev=false;
	char s[10];
	int u, v;
	for1(i, 1, n) {
		nd[i]=new node;
		nd[i]->fa=nd[i]->ch[0]=nd[i]->ch[1]=null; nd[i]->rev=false;
	}
	rep(i, m) {
		scanf("%s", s);
		read(u); read(v);
		if(s[0]==‘Q‘)
			findrt(nd[u])==findrt(nd[v])?(printf("Yes\n")):(printf("No\n"));
		else if(s[0]==‘C‘) link(nd[u], nd[v]);
		else cut(nd[u], nd[v]);
	}

	return 0;
}

欢迎大家指正~!!!

动态树之link-cut tree

时间: 2024-10-25 04:48:11

动态树之link-cut tree的相关文章

LuoguP3690 【模板】Link Cut Tree (动态树) LCT模板

P3690 [模板]Link Cut Tree (动态树) 题目背景 动态树 题目描述 给定n个点以及每个点的权值,要你处理接下来的m个操作.操作有4种.操作从0到3编号.点从1到n编号. 0:后接两个整数(x,y),代表询问从x到y的路径上的点的权值的xor和.保证x到y是联通的. 1:后接两个整数(x,y),代表连接x到y,若x到y已经联通则无需连接. 2:后接两个整数(x,y),代表删除边(x,y),不保证边(x,y)存在. 3:后接两个整数(x,y),代表将点x上的权值变成y. 输入输出

P3690 【模板】Link Cut Tree (动态树)

P3690 [模板]Link Cut Tree (动态树) https://www.luogu.org/problemnew/show/P3690 分析: LCT模板 代码: 注意一下cut! 1 #include<cstdio> 2 #include<algorithm> 3 4 using namespace std; 5 6 const int N = 300100; 7 8 int val[N],fa[N],ch[N][2],rev[N],sum[N],st[N],top;

脑洞大开加偏执人格——可持久化treap版的Link Cut Tree

一直没有点动态树这个科技树,因为听说只能用Splay,用Treap的话多一个log.有一天脑洞大开,想到也许Treap也能从底向上Split.仔细思考了一下,发现翻转标记不好写,再仔细思考了一下,发现还是可以写的,只需要实时交换答案二元组里的两棵树,最后在吧提出来的访问节点放回去就行了.本着只学一种平衡树的想法,脑洞大开加偏执人格的开始写可持久化Treap版的Link Cut Tree... 写了才发现,常数硕大啊!!!代码超长啊!!!因为merge是从上到下,split从下到上,pushdow

Link Cut Tree学习笔记

从这里开始 动态树问题和Link Cut Tree 一些定义 access操作 换根操作 link和cut操作 时间复杂度证明 Link Cut Tree维护链上信息 Link Cut Tree维护子树信息 小结 动态树问题和Link Cut Tree 动态树问题是一类要求维护一个有根树森林,支持对树的分割, 合并等操作的问题. Link Cut Tree(林可砍树?简称LCT)是解决这一类问题的一种数据结构. 一些无聊的定义 Link Cut Tree维护的是动态森林中每棵树的任意链剖分. P

bzoj2049 [Sdoi2008]Cave 洞穴勘测 link cut tree入门

link cut tree入门题 首先说明本人只会写自底向上的数组版(都说了不写指针.不写自顶向下QAQ……) 突然发现link cut tree不难写... 说一下各个函数作用: bool isroot(int x):判断x是否为所在重链(splay)的根 void down(int x):下放各种标记 void rotate(int x):在x所在重链(splay)中将x旋转到fa[x]的位置上 void splay(int x):在x坐在重链(splay)中将x旋转到根 void acce

link cut tree 入门

鉴于最近写bzoj还有51nod都出现写不动的现象,决定学习一波厉害的算法/数据结构. link cut tree:研究popoqqq那个神ppt. bzoj1036:维护access操作就可以了. #include<cstdio> #include<cstring> #include<cctype> #include<algorithm> #include<queue> using namespace std; #define rep(i,s,

HDOJ 题目3966 Aragorn&#39;s Story(Link Cut Tree成段加减点权,查询点权)

Aragorn's Story Time Limit: 10000/3000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 5505    Accepted Submission(s): 1441 Problem Description Our protagonist is the handsome human prince Aragorn comes from The Lor

Link Cut Tree(无图慎入)

类似树链剖分(其实直接记住就可以了),提前放代码 1 #include<cstdio> 2 #include<cstdlib> 3 #include<iostream> 4 #include<algorithm> 5 #include<cstring> 6 #include<climits> 7 #include<cmath> 8 #define N (int)(3e5+5) 9 using namespace std;

Codeforces Round #339 (Div. 2) A. Link/Cut Tree

A. Link/Cut Tree Programmer Rostislav got seriously interested in the Link/Cut Tree data structure, which is based on Splay trees. Specifically, he is now studying the expose procedure. Unfortunately, Rostislav is unable to understand the definition

AC日记——【模板】Link Cut Tree 洛谷 P3690

[模板]Link Cut Tree 思路: LCT模板: 代码: #include <bits/stdc++.h> using namespace std; #define maxn 300005 int n,m,val[maxn]; int top,ch[maxn][2],f[maxn],xr[maxn],q[maxn],rev[maxn]; inline void in(int &now) { int if_z=1;now=0; char Cget=getchar(); while