首页 > 其他 > 详细

动态树之link-cut tree

时间:2014-08-18 12:23:24      阅读:680      评论:0      收藏:0      [点我收藏+]

说好的专题。。。

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,布布扣,bubuko.com

动态树之link-cut tree

原文:http://www.cnblogs.com/iwtwiioi/p/3919083.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!