淺談伸展樹(Splay)

//本文是一個暫時的小記,有不對的請大佬們指出~
真正大佬的在這http://blog.csdn.net/clove_unique/article/details/50630280

伸展樹(Splay Tree),也叫分裂樹,是一種二叉排序樹,它能在O(log n)內完成插入、查找和刪除操作。它由丹尼爾·斯立特Daniel Sleator和羅伯特·恩卓·塔揚Robert Endre Tarjan在1985年發明的。
在伸展樹上的一般操作都基於伸展操作:假設想要對一個二叉查找樹執行一系列的查找操作,爲了使整個查找時間更小,被查頻率高的那些條目就應當經常處於靠近樹根的位置。於是想到設計一個簡單方法, 在每次查找之後對樹進行重構,把被查找的條目搬移到離樹根近一些的地方。伸展樹應運而生。伸展樹是一種自調整形式的二叉查找樹,它會沿着從某個節點到樹根之間的路徑,通過一系列的旋轉把這個節點搬移到樹根去。
它的優勢在於不需要記錄用於平衡樹的冗餘信息。

(本段來自百度)
##Splay的基本操作

  • get操作
    主要用來查找x結點屬於其父親結點的左兒子還是右兒子
int get(int x)
{
	return son[fa[x]][1]==x;
}
  • update操作
    主要是更新size值
    (有的時候也會更新其他)
void update(int x)
{  
     if (x)
     {  
		  size[x]=1; 
          if (son[x][0]) size[x]+=size[son[x][0]];  
          if (son[x][1]) size[x]+=size[son[x][1]]; 
     }  
}  
  • rotate(旋轉)操作
    這是Splay最常用也是最重要的操作了
    具體的操作就是找到x與父親的關係(是他的左兒子還是右兒子),然後旋上去,直接取代其父親的位置,然後進行一系列的“兒子認領“(具體看代碼)
int rotate(int x)
{
	int k=get(x),y=fa[x];
	if(fa[y])son[fa[y]][get(y)]=x;
	if(son[x][!k])fa[son[x][!k]]=y;//x結點反方向的兒子
	fa[x]=fa[y],fa[y]=x,son[y][k]=son[x][!k],son[x][!k]=y;//認領兒子
	update(y),update(x);
}

然後來一道例題,相信用線段樹做過【最大值】,此題甚好,但是又有了區間修改,變成了【最大值2】,現在用Splay實現:
題目不記得了吧~
##Description
 在N(1<=N<=100000)個數A1…An組成的序列上進行M(1<=M<=100000)次操作,操作有兩種:
  (1)1 L R C:表示把A[L]到A[R]增加C(C的絕對值不超過10000);
  (2)2 L R:詢問A[L]到A[R]之間的最大值。
####思考一下~
好的,那麼我們只需要在上面講的所有裏面加入一個打標記的操作就好了。
這和線段樹的差不多,打完這個標記lazy,下傳~

#include<cstdio>
#include<iostream>
#define LL long long
using namespace std;
int son[100001][2];//Son
LL fmax[100001];//Ans
int fa[100001];//Father
LL add[100001];//Lazy
LL a[100001];//Data
int d[100001];//Queue
int n,m,kind,l,r,c;
int update(int x){fmax[x]=max(a[x],max(fmax[son[x][0]],fmax[son[x][1]]));}
int lazy(int x,int c){fmax[x]+=c,a[x]+=c,add[x]+=c;}
int get(int x){return son[fa[x]][1]==x;}
int clear(int x)
{
	if(son[x][0])lazy(son[x][0],add[x]);
	if(son[x][1])lazy(son[x][1],add[x]);
	add[x]=0;
}
int remove(int x,int y)
{
	d[0]=0;
	for (x=x;x-y;x=fa[x]) d[++d[0]]=x;
	while (d[0]) clear(d[d[0]--]);	
}
int rotate(int x)
{
	int k=get(x),y=fa[x];
	if(fa[y])son[fa[y]][get(y)]=x;
	if(son[x][!k])fa[son[x][!k]]=y;
	fa[x]=fa[y],fa[y]=x,son[y][k]=son[x][!k],son[x][!k]=y;
	update(y),update(x);
}
int Splay(int x,int y)
{
	remove(x,y);
	while(fa[x]-y)
	{
		if(fa[fa[x]]-y)
			if(get(x)==get(fa[x])) rotate(fa[x]);
			else rotate(x);
		rotate(x);
	}
}
int main()
{
	freopen("Max2.in","r",stdin);
	scanf("%d",&n);
	int i;fmax[0]=-1e9;
	for (i=1;i<=n;++i)
		scanf("%lld",&a[i+1]),fa[i]=i+1,son[i+1][0]=i,update(i+1);
	fa[n+1]=n+2,son[n+2][0]=n+1,update(n+2);
	scanf("%d",&m);
	for (i=1;i<=m;++i)
	{
		scanf("%d%d%d",&kind,&l,&r);++l,++r;
		Splay(l-1,0),Splay(r+1,l-1);
		if(kind-2){scanf("%d",&c),lazy(son[r+1][0],c);}
		else printf("%lld\n",fmax[son[r+1][0]]);
	}
}

JZOJ【NOIP2015模擬9.12】平方和

#include<cstdio>
#include<iostream>
#define maxn 200010
#define mo 7459
#define ll long long
using namespace std;
struct Moon{
	ll tag,key,size;
	ll sum,sum2,fa;
}t[4*maxn];
ll son[maxn][2],d[maxn];
ll n,a[maxn],m,x,y,z,root,sz;
ll get(ll x)
{
	return son[t[x].fa][1]==x;
}
void update(ll x)
{
 	t[x].size=t[son[x][0]].size+t[son[x][1]].size+1;
	(t[x].sum=t[son[x][0]].sum+t[son[x][1]].sum+t[x].key)%=mo;
	(t[x].sum2=t[son[x][0]].sum2+t[son[x][1]].sum2+t[x].key*t[x].key)%=mo;
}
ll findx(ll num)
{
	ll v=root;
	while(x)
	{
		if(son[v][0]&&t[son[v][0]].size>=num) v=son[v][0];
		else 
		{
			ll cnt=t[son[v][0]].size+1;
			if(cnt==num) return v;
			num-=cnt;
			v=son[v][1];
		}
	}
	return v;
}
void rotate(ll x)
{
	ll k=get(x),y=t[x].fa;
	if(t[y].fa) son[t[y].fa][get(y)]=x;
	if(son[x][!k]) t[son[x][!k]].fa=y;
	t[x].fa=t[y].fa,son[y][k]=son[x][!k];
	son[x][!k]=y,t[y].fa=x;
	update(y),update(x);
}
ll Sum(ll x,ll b)
{
	ll ans=((t[x].sum2+2*b*t[x].sum)%mo+t[x].size*b*b%mo)%mo;
	return ans;
}
void clear(ll x)
{
	if(t[x].tag)
	{
		for (ll i=0;i<=1;++i)
		{
			if(!son[x][i]) continue;
			(t[son[x][i]].key+=t[x].tag)%=mo;
			(t[son[x][i]].tag+=t[x].tag)%=mo;
			t[son[x][i]].sum2=Sum(son[x][i],t[x].tag%mo);
			(t[son[x][i]].sum+=t[son[x][i]].size*t[x].tag)%=mo;
		}
		t[x].tag=0;
	}
}
void remove(ll x,ll y)
{
	d[0]=0;
	for (;x!=y;x=t[x].fa) d[++d[0]]=x;
	for (ll i=d[0];i>=1;--i) clear(d[i]);
} 
void splay(ll x,ll y)
{
	remove(x,y);
	while(t[x].fa!=y)
	{
		if(t[t[x].fa].fa!=y) 
			if(get(x)==get(t[x].fa)) rotate(t[x].fa);
			else rotate(x);
		rotate(x);
	}
	if(y==0) root=x;
}
void add(ll x,ll c)
{
	(t[x].key+=c)%=mo;
	(t[x].tag+=c)%=mo;
	t[x].sum2=Sum(x,c);
	(t[x].sum+=t[x].size*c%mo)%=mo;
}
int main()
{
	scanf("%lld",&n);
	ll i,j,xx,yy;char k;
	for (i=1;i<=n;++i) scanf("%lld",&a[i+1]);
	for (i=2;i<=n+2;++i) son[i][0]=i-1,t[i-1].fa=i,t[i-1].key=a[i-1],update(i-1);
	update(n+2);
	scanf("%lld\n",&m);root=sz=n+2;
	for (i=1;i<=m;++i)
	{
		scanf("%c",&k);
		if(k=='Q')
		{
			scanf("uery%lld%lld\n",&x,&y);++x,++y;
			yy=findx(y+1),xx=findx(x-1);
			splay(xx,0);
			splay(yy,xx);
			printf("%lld\n",(t[son[yy][0]].sum2+mo)%mo);
		}
		if(k=='I')
		{
			scanf("nsert%lld%lld\n",&x,&y);++x; 
			xx=findx(x-1),yy=findx(x);
			splay(xx,0),splay(yy,xx);
			son[yy][0]=++sz,t[sz].fa=yy;
			t[sz].key=t[sz].sum=y,t[sz].sum2=y*y%mo,t[sz].size=1;
			update(yy),update(xx);
		}
		if(k=='A')
		{
			scanf("dd%lld%lld%lld\n",&x,&y,&z);++x,++y;
			yy=findx(y+1),xx=findx(x-1);
			splay(xx,0),splay(yy,xx);
			add(son[yy][0],z);
		}
	}
}

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