數據結構入門6—文藝平衡樹(Splay)

早就聽說 Splay 就是不管幹什麼都Splay一下就可以了,但是聽說傻可開腦洞打代碼打了250行,驚恐。

於是先學treap結果沒想到一調試就搞了三個月。但是其實寫過treap再學Splay就相對容易一些了。

那就先學只有區間翻轉的文藝平衡樹。

一開始一直弄不懂它的翻轉操作,感覺很迷。但是其實和treap很像,只不過是以翻兩下爲一組,然後每次Splay把節點旋到指定位置。在三點一線的時候,先旋轉x的父親,再旋轉x,除此之外都直接旋轉x就好了。

除此之外還要注意一些細節問題。一個是關於添加虛節點的問題。比如我們要翻轉[l,r]這個區間,我們可以把r+1這個點Splay到跟,然後把l-1這個點Splay到跟的左兒子,然後直接把l-1的右兒子打上標記。但是如果l==1或r==n,那樣就必須添加一個能表示l-1(0)的節點和一個能表示r+1(n+1)的節點。

Splay有兩種寫法,白書上是沒有父親指針的,但是有父親指針的適用性更強。

模板題

//Serene
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<cstdio>
#include<cmath>
using namespace std;
const int maxn=1e5+10;
int n,m,root;

int aa;char cc;
int read() {
	aa=0;cc=getchar();
	while(cc<'0'||cc>'9') cc=getchar();
	while(cc>='0'&&cc<='9') aa=aa*10+cc-'0',cc=getchar();
	return aa;
}

struct Node{
	int son[2],laz,fa,sum;
}node[maxn];

void bld(int pos,int l,int r) {
	if(!pos||l>r) return ;
	if(l==r) {node[pos].sum=1;return;}
	if(pos!=l) node[pos].son[0]=(pos+l)>>1;
	if(pos!=r) node[pos].son[1]=(pos+2+r)>>1;
	node[node[pos].son[0]].fa=node[node[pos].son[1]].fa=pos;
	bld(node[pos].son[0],l,pos-1); bld(node[pos].son[1],pos+1,r);
	node[pos].sum+=node[node[pos].son[0]].sum+node[node[pos].son[1]].sum+1;
}

void ud(int pos) {
	if(!node[pos].laz||node[pos].sum==1) {
		node[pos].laz=0;return ;//
	}
	swap(node[pos].son[0],node[pos].son[1]);
	if(node[pos].son[0]) node[node[pos].son[0]].laz^=1;
	if(node[pos].son[1]) node[node[pos].son[1]].laz^=1;
	node[pos].laz=0;
}

int find(int pos,int x) {
	ud(pos);
	if(node[node[pos].son[0]].sum+1==x) return pos;
	if(x<=node[node[pos].son[0]].sum) return find(node[pos].son[0],x);
	return find(node[pos].son[1],x-(node[node[pos].son[0]].sum+1));
}

void rotate(int pos,int &to) {
	int x=node[pos].fa,y=node[x].fa;
	int p1=node[x].son[1]==pos,p2=node[y].son[1]==x;
	node[x].son[p1]=node[pos].son[!p1];
	node[node[pos].son[!p1]].fa=x;// 
	node[pos].son[!p1]=x;
	node[pos].sum=node[x].sum;
	node[x].sum=node[node[x].son[0]].sum+node[node[x].son[1]].sum+1;
	node[pos].fa=y;node[x].fa=pos;
	if(root==x) root=pos;
	else {
		node[y].son[p2]=pos;
		if(x==to) to=pos;	
	}
}

void splay(int pos,int &to) {
	ud(pos);
	int x,y,p1,p2;
	while(to!=pos) {
		x=node[pos].fa;y=node[x].fa;
		if(y) ud(y);ud(x);ud(pos);
		if(x!=to) {
			if(node[x].son[1]==pos ^ node[y].son[1]==x) rotate(pos,to);
			else rotate(x,to);
		}
		rotate(pos,to);
	}
}

void fz(int l,int r) {
	if(l==r) return ;
	int x=find(root,l),y=find(root,r+2);
	splay(y,root); splay(x,node[root].son[0]);
	node[node[x].son[1]].laz^=1;
}

void dfs(int pos) {
	ud(pos);
	if(node[pos].son[0]) dfs(node[pos].son[0]);
	if(pos>1&&pos<n+2) printf("%d ",pos-1);
	if(node[pos].son[1]) dfs(node[pos].son[1]);
}

int main() {
	n=read();m=read();
	root=(n+3)>>1;
	bld(root,1,n+2);
	int l,r;
	for(int i=1;i<=m;++i) {
		l=read();r=read();
		fz(l,r);
	}
	dfs(root);
	return 0;
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章