【SPLAY】SPOJ1470維護數列

       BZOJ跪了我找了好多OJ才又找到維護數列這個題~話說SPOJ好像比較慢的樣子~我找別人以前在BZOJ上AC的程序在SPOJ上竟然TLE了~加了讀入優化還是TLE~囧~這算個什麼事~今天把splay的數組實現改成了指針實現以後終於AC掉了~完全不知道我的splay哪裏寫慢了QAQ

       splay總體來說就是轉來轉去轉來轉去【轉暈了誒】各種操作都是在旋轉的基礎上完成的。splay因爲不需要維護樹的嚴格平衡,可以實現很多其它平衡樹不能完成的操作。總體來說splay的功能有如下一些:

       單點插入、查詢、刪除(所有平衡樹都可以)

       單點、成段更新(其它平衡樹不能、線段樹和splay可以)(呃~好像其它平衡樹可以單點更新的樣子呢喵)

       成段插入、刪除、區間翻轉(其它平衡樹和線段樹都不能,只有splay可以)

       也就是說,splay可以代替線段樹,但是和線段樹比起來代碼量過大了QAQ

對區間的操作方式是:把區間左端點的左邊一位轉到根,右端點的右邊一位轉到根的右子樹,這樣根的右子樹的左子樹就是要操作的區間。開始建樹時要在樹上建兩-INF的結點保證區間的兩個端點一定存在。

2012-12-26

關於splay的雙旋轉,要這樣旋轉的原因是爲了維護splay的相對平衡,如果總是轉x結點一直轉到根那麼一條鏈轉完以後還是一條鏈,而使用雙旋轉則可以使旋轉後的splay變得相對平衡。這一部分在楊思雨的論文裏有詳細的圖解。

更具體一些的可以圍觀Crash神的論文

囧~話說平衡樹我是先學的SBT,沒學splay是因爲我當時不會線段樹,本來是要交給蛋蛋去學的~然後我之所以不會線段樹是因爲覺得他倆都會了我就不學了QAQ然後~我還是學了~學完以後發現這玩意好簡單……然後開始折騰splay【是這貨折騰我】……理論到是不難~寫起來還真是各種糾結~圍觀了Crash神的論文和各位神的代碼終於搞明白了OTL

下面送上我的splay模板~個人覺得寫得還是很清晰的~

/*
    插入:INSERT pos n c1...cn (pos後面插入n個數字)
    刪除:DELETE pos n (刪除pos開始的n個數字)
    修改:MAKE-SAME pos n c (pos開始的n個數字修改爲c)
    翻轉:REVERSE pos n (pos開始的n個數字翻轉)
    求和:GET-SUM pos n (pos開始的n個數字求和)
    求和最大的子序列:MAX-SUM (整個區間的和最大的子序列)
*/
#include <cstdio>
#include <iostream>
using namespace std;
#define INF 1<<30
#define N 500010
int n,m;
int num[N];
struct node
{
	node *ch[2],*pre;
	int sz,val,sum,ls,rs,ss;
	bool lzy1;
	int lzy2;
};
struct SplayTree
{
	node *root,*null,*pool[N],data[N];
	int n,cnt,top;
	void rotate(node *x,int f)//旋轉
	{
		node *y=x->pre,*z=y->pre;
		push_down(y);
		push_down(x);
		y->ch[!f]=x->ch[f];
		x->ch[f]->pre=y;
		x->ch[f]=y;
		y->pre=x;
		x->pre=z;
		if(x->pre!=null) z->ch[z->ch[1]==y]=x;
		push_up(y);
	}
	void splay(node *x,node *goal)//把x節點轉到goal下面,goal爲0表示轉到根
	{
		push_down(x);
		while (x->pre!=goal)
		{
			if(x->pre->pre==goal) rotate(x,x->pre->ch[0]==x);
			else
			{
				node *y=x->pre,*z=y->pre;
				int f=(z->ch[0]==y);
				if(y->ch[f]==x) rotate(x,!f);
				else rotate(y,f);
				rotate(x,f);
			}
		}
		push_up(x);
		if(goal==null) root=x;
	}
	void rotateto(int k,node *goal)//把第k位轉到goal下面
	{
		node *x=root;
		push_down(x);
		while (x->ch[0]->sz!=k)
		{
			if(k<x->ch[0]->sz) x=x->ch[0];
			else{
				k-=x->ch[0]->sz+1;
				x=x->ch[1];
			}
			push_down(x);
		}
		splay(x,goal);
	}
	//以上函數基本不用變
	void clear()
	{
		n=top=0;
		null=newnode(-INF);
		null->sz=null->sum=0;
		null->val=null->ls=null->rs=null->ss=-INF;
		null->lzy1=0;
		null->lzy2=-INF;
		root=newnode(-INF);
		root->ch[1]=newnode(-INF);
		root->ch[1]->pre=root;
		root->sz=2;
	}
	node *newnode(int c)
	{
		node *x;
		if (top) x=pool[top--];
		else x=&data[n++];
		x->ch[0]=x->ch[1]=x->pre=null;
		x->sz=1;
		x->val=x->ls=x->rs=x->ss=x->sum=c;
		x->lzy1=0;
		x->lzy2=-INF;
		return x;
	}
	void push_up(node *x)
	{
		node *lx=x->ch[0],*rx=x->ch[1];
		
		x->sz=1+lx->sz+rx->sz;
		x->sum=x->val+lx->sum+rx->sum;
		
		x->ls=max(lx->ls,lx->sum+x->val+max(0,rx->ls));
		x->rs=max(rx->rs,rx->sum+x->val+max(0,lx->rs));
		
		x->ss=max(0,lx->rs)+x->val+max(0,rx->ls);
		x->ss=max(x->ss,max(lx->ss,rx->ss));
	}
	void update_rev(node *x)
	{
		if(x==null) return;
		swap(x->ch[0],x->ch[1]);
		swap(x->ls,x->rs);
		x->lzy1^=1;
	}
	void update_same(node *x,int v)
	{
		if(x==null) return;
		x->val=v;
		x->sum=v*x->sz;
		x->ss=x->ls=x->rs=max(v,v*x->sz);
		x->lzy2=v;
	}
	void push_down(node *x)
	{
		if(x->lzy1)
		{
			update_rev(x->ch[0]);
			update_rev(x->ch[1]);
			x->lzy1=0;
		}
		if(x->lzy2!=-INF)
		{
			update_same(x->ch[0],x->lzy2);
			update_same(x->ch[1],x->lzy2);
			x->lzy2=-INF;
		}
	}
	void init(int pos,int tot)
	{
		clear();
		cnt=tot;
		rotateto(pos,null);
		rotateto(pos+1,root);
		root->ch[1]->ch[0]=build(1,tot,root->ch[1]);
		push_up(root->ch[1]);
		push_up(root);
	}
	node *build(int l,int r,node *f)
	{
		if(l>r) return null;
		push_down(f);
		int mid=(l+r)>>1;
		node *x=newnode(num[mid]);
		x->ch[0]=build(l,mid-1,x);
		x->ch[1]=build(mid+1,r,x);
		x->pre=f;
		push_up(x);
		return x;
	}
	void ins(int pos,int len)
	{
		cnt+=len;
		rotateto(pos,null);
		rotateto(pos+1,root);
		root->ch[1]->ch[0]=build(1,len,root->ch[1]);
		push_up(root->ch[1]);
		push_up(root);
	}
	void erase(node *x)
	{
		if(x==null) return;
		pool[++top]=x;
		erase(x->ch[0]);
		erase(x->ch[1]);
	}
	void del(int l,int r)
	{
		rotateto(l-1,null);
		rotateto(r+1,root);
		node *key=root->ch[1]->ch[0];
		root->ch[1]->ch[0]=null;
		cnt-=key->sz;
		erase(key);
		push_up(root->ch[1]);
		push_up(root);
	}
	void change(int l,int r,int c)
	{
		rotateto(l-1,null);
		rotateto(r+1,root);
		node *key=root->ch[1]->ch[0];
		update_same(key,c);
		push_up(root->ch[1]);
		push_up(root);
	}
	void flip(int l,int r)
	{
		rotateto(l-1,null);
		rotateto(r+1,root);
		node *key=root->ch[1]->ch[0];
		update_rev(key);
	}
	int get_sum(int l,int r)
	{
		rotateto(l-1,null);
		rotateto(r+1,root);
		node *key=root->ch[1]->ch[0];
		return key->sum;
	}
	int max_sum()
	{
		rotateto(0,null);
		rotateto(cnt+1,root);
		node *key=root->ch[1]->ch[0];
		return key->ss;
	}
	void print(node *x)
	{
		if(x->ch[0]!=null) print(x->ch[0]);
		printf("%d ",x->val);
		if(x->ch[1]!=null) print(x->ch[1]);
	}
}spl;
int main ()
{
	 int tt;
	 int i,j,t;
	 int a,b,c;
	 char op[30];
	 scanf("%d",&tt);
	 while (tt--)
	 {
	 	scanf("%d%d",&n,&m);
	 	for(i=1;i<=n;i++) scanf("%d",&num[i]);
	 	spl.init(0,n);
	 	/*spl.print(spl.root);
	 	printf("\n");
	 	return 0;*/
	 	while (m--)
	 	{
	 		scanf("%s",op);
	 		if(op[0]=='I')
	 		{
	 			scanf("%d%d",&a,&n);
	 			for(i=1;i<=n;i++) scanf("%d",&num[i]);
	 			spl.ins(a,n);
	 		}else
	 		if(op[0]=='D')
	 		{
	 			scanf("%d%d",&a,&b);
	 			spl.del(a,a+b-1);
	 		}else
	 		if(op[0]=='M' && op[2]=='K')
	 		{
	 			scanf("%d%d%d",&a,&b,&c);
	 			spl.change(a,a+b-1,c);
	 		}else
	 		if(op[0]=='R')
	 		{
	 			scanf("%d%d",&a,&b);
	 			spl.flip(a,a+b-1);
	 		}else
	 		if(op[0]=='G')
	 		{
	 			scanf("%d%d",&a,&b);
	 			printf("%d\n",spl.get_sum(a,a+b-1));
	 		}
	 		else if(op[0]=='M') printf("%d\n",spl.max_sum());
	 	}
	 }
	
	return 0;
}


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