Splay伸展树模板总结

1.基本点操作

//Splay 基本操作 均摊复杂度O(lgN) 

//POJ 1442
//基本点操作


// sp.init()	初始化



#include <iostream>
#include <algorithm>
#include <cmath>

using namespace std;

#define maxn 31000
#define min(a,b) ((a)<(b)?(a):(b))
const int oo = 0x3f3f3f3f;
struct Node{
    int key, sz, cnt;
    Node *ch[2], *pnt;//左右儿子和父亲
    Node(){}
    Node(int x, int y, int z){
    key = x, sz = y, cnt = z;
    }
    void rs(){
    sz = ch[0]->sz + ch[1]->sz + cnt;
    }
}nil(0, 0, 0), *NIL = &nil;
struct Splay{//伸展树结构体类型
    Node *root;
    int ncnt;//计算key值不同的结点数,注意已经去重了
    Node nod[maxn];
    void init(){// 首先要初始化
        root = NIL;
        ncnt = 0;
    }
    void rotate(Node *x, bool d){//旋转操作,d为true表示右旋
        Node *y = x->pnt;
        y->ch[!d] = x->ch[d];
        if (x->ch[d] != NIL)
            x->ch[d]->pnt = y;
        x->pnt = y->pnt;
        if (y->pnt != NIL){
            if (y == y->pnt->ch[d])
                y->pnt->ch[d] = x;
            else
                y->pnt->ch[!d] = x;
        }
        x->ch[d] = y;
        y->pnt = x;
        y->rs();
        x->rs();
    }
    void splay(Node *x, Node *target){//将x伸展到target的儿子位置处
        Node *y;
        while (x->pnt != target){
            y = x->pnt;
            if (x == y->ch[0]){
                if (y->pnt != target && y == y->pnt->ch[0])
                    rotate(y, true);
                    rotate(x, true);
            }
            else{
                if (y->pnt != target && y == y->pnt->ch[1])
                    rotate(y, false);
                    rotate(x, false);
            }
        }
        if (target == NIL)
            root = x;
    }
    /************************以上一般不用修改************************/
    void insert(int key){//插入一个值
        if (root == NIL){
            ncnt = 0;
            root = &nod[++ncnt];
            root->ch[0] = root->ch[1] = root->pnt = NIL;
            root->key = key;
            root->sz = root->cnt = 1;
            return;
        }
        Node *x = root, *y;
        while (1){
            x->sz++;
            if (key == x->key){
                x->cnt++;
                x->rs();
                y = x;
                break;
            }
            else if (key < x->key){
                    if (x->ch[0] != NIL)
                        x = x->ch[0];
                    else{
                        x->ch[0] = &nod[++ncnt];
                        y = x->ch[0];
                        y->key = key;
                        y->sz = y->cnt = 1;
                        y->ch[0] = y->ch[1] = NIL;
                        y->pnt = x;
                        break;
                    }
            }
            else{
                if (x->ch[1] != NIL)
                    x = x->ch[1];
                else{
                    x->ch[1] = &nod[++ncnt];
                    y = x->ch[1];
                    y->key = key;
                    y->sz = y->cnt = 1;
                    y->ch[0] = y->ch[1] = NIL;
                    y->pnt = x;
                    break;
                }
            }
        }
        splay(y, NIL);
    }
    Node* search(int key){//查找一个值,返回指针
        if (root == NIL)
            return NIL;
        Node *x = root, *y = NIL;
        while (1){
            if (key == x->key){
                y = x;
                break;
            }
            else if (key > x->key){
                if (x->ch[1] != NIL)
                x = x->ch[1];
                else
                    break;
            }
            else{
                if (x->ch[0] != NIL)
                    x = x->ch[0];
                else
                    break;
            }
        }
        splay(x, NIL);
        return y;
    }
    Node* searchmin(Node *x){//查找最小值,返回指针
        Node *y = x->pnt;
        while (x->ch[0] != NIL){//遍历到最左的儿子就是最小值
            x = x->ch[0];
        }
            splay(x, y);
            return x;
    }
    Node* searchmax(Node *x){
		Node *y = x->pnt;
		while(x->ch[1] != NIL){
			x = x->ch[1];
		} 
			splay(x,y);
			return x;
	} 
    void del(int key){//删除一个值
        if (root == NIL)
            return;
        Node *x = search(key), *y;
        if (x == NIL)
            return;
        if (x->cnt > 1){
            x->cnt--;
            x->rs();
            return;
        }
        else if (x->ch[0] == NIL && x->ch[1] == NIL){
            init();
            return;
        }
        else if (x->ch[0] == NIL){
            root = x->ch[1];
            x->ch[1]->pnt = NIL;
            return;
        }
        else if (x->ch[1] == NIL){
            root = x->ch[0];
            x->ch[0]->pnt = NIL;
            return;
        }
        y = searchmin(x->ch[1]);
        y->pnt = NIL;
        y->ch[0] = x->ch[0];
        x->ch[0]->pnt = y;
        y->rs();
        root = y;
    }
    int rank(int key){//求结点高度
        Node *x = search(key);
        if (x == NIL)
            return 0;
        return x->ch[0]->sz + 1/* or x->cnt*/;
    }
    Node* findk(int kth){//查找第k小的值
        if (root == NIL || kth > root->sz)
            return NIL;
        Node *x = root;
        while (1){
            if (x->ch[0]->sz +1 <= kth && kth <= x->ch[0]->sz + x->cnt)
                break;
            else if (kth <= x->ch[0]->sz)
                x = x->ch[0];
            else{
                kth -= x->ch[0]->sz + x->cnt;
                x = x->ch[1];
            }
        }
        splay(x, NIL);
        return x;
    }
    
    Node* proc(int key)
    {
		Node *x = search(key);
		if(x==NIL || x->cnt == 1 && x->ch[0]==NIL)
		{
			return NIL;	
		}
		if(x->cnt > 1)
		{
			return x;
		}
		else
		{
			return searchmax(x->ch[0]);
		}
	}
	
	Node* succ(int key)
	{
		Node *x = search(key);
		if(x==NIL || x->cnt == 1 && x->ch[1]==NIL)
		{
			return NIL;
		}
		if(x->cnt > 1)
		{
			return x;
		}
		else
		{
			return searchmin(x->ch[1]);
		}
	}
	
	int size()
	{
		return root->sz;
	}
}sp;
int num[30010];
int cmd[30010];
int main(){
   	
   	ios::sync_with_stdio(false);
	int N,M,x,i;
	while(cin >> N >> M)
	{
		sp.init();
		for(int i=0;i<N;i++)
		{
			cin >> num[i];
		}
		for(int i=1;i<=M;i++)
		{
			cin >> cmd[i];
		}
		int j=1;
		Node* node;
		for(int i=0;i<N;i++)
		{
			sp.insert(num[i]);
			while(sp.size()==cmd[j])
			{
				node = sp.findk(j++);
				cout << node->key << endl;
			}
		}
		
	}
   	
    return 0;
}

2.基本区间操作

/*
_http://acm.hdu.edu.cn/showproblem.php?pid=3487_
1.区间切割 区间翻转      
原序列:	1、2、3 ……n 
rangeCut(a,b,c)	将[ath,bth]剪切掉 然后黏贴到新序列的第cth后面 
rangeFlip(a,b)	翻转[ath,bth] 



_http://acm.hdu.edu.cn/showproblem.php?pid=1754_
2.单点更新 区间询问最值 	
query(a,b)	询问[a,b]最大值
update(a,c)	更新学生a的成绩为c 



_http://poj.org/problem?id=3468_
3.区间更新 区间求和
querySum(l,r)	询问[l,r]的和 
updateInterval(l,r,c)	区间[l,r]的值+c 

*/ 
#include<iostream>
#include<cstdio>
#include<cstring>
#define LL long long
using namespace std;
const int MAXN = 333333;
#define m_set(ptr,v,type,size) memset(ptr,v,sizeof(type) * size)
#define loop(begin,end) for(int i=begin;i<end;i++)
#define debug	puts("here!")
class SplayTree
{
	#define l(x) (ch[x][0])
	#define r(x) (ch[x][1])
	#define mid(x,y)	((x+y)>>1)
	public:
		int ch[MAXN][2],pre[MAXN];
		int sz[MAXN],val[MAXN],rev[MAXN],a[MAXN];
		int root,tot;
		
		/**************/
		
		int mx[MAXN];
		
		/**************/ 
		
		LL sum[MAXN],add[MAXN];
		
		/**************/
		
		void init()
		{
			m_set(ch,0,int,MAXN*2);
			m_set(pre,0,int,MAXN);
			m_set(sz,0,int,MAXN);
			m_set(val,0,int,MAXN);
			m_set(rev,0,int,MAXN);
			
			/*************/
			m_set(mx,-1,int,MAXN);
			/*************/
			root = tot = 0;
		}
		
		void read(int n)		//0 1 2 3 .... n 0
		{
			a[1] = a[n+2] = -1;
//			loop(2,n+2){
//				a[i] = i - 1;
//			}	

			/*************/
			for(int i=2;i<=n+1;i++)
			{
				scanf("%d",&a[i]);
			}
			/*************/
		}
		
		void push_up(int rt)
		{
			sz[rt] = sz[l(rt)] + sz[r(rt)] + 1;
			/*************/
			mx[rt] = max(max(mx[l(rt)],mx[r(rt)]),val[rt]);
			/*************/
			sum[rt] = sum[l(rt)] + sum[r(rt)] + val[rt];
		} 
		
		void push_down(int rt)
		{
//			if(rt&&rev[rt])
//			{
//				swap(l(rt),r(rt));
//				if(l(rt))	rev[l(rt)] ^= 1;
//				if(r(rt))	rev[r(rt)] ^= 1;
//				rev[rt] = 0;
//			}
		
			if(add[rt])
			{
				if(l(rt))
				{
					val[l(rt)] += add[rt];
					add[l(rt)] += add[rt];
					sum[l(rt)] += add[rt] * sz[l(rt)];
				}
				if(r(rt))
				{
					val[r(rt)] += add[rt];
					add[r(rt)] += add[rt];
					sum[r(rt)] += add[rt] * sz[r(rt)]; 
				}
				add[rt] = 0;
			}			
		}
			
		void swap(int &x,int &y)
		{
			int tmp = x;
			x = y;
			y = tmp;
		}
		
	
		void rotate(int x,int f)	//将x旋转到其直接父节点 右旋 左旋 
		{
			int y  = pre[x];
			push_down(x);
			push_down(y);
			ch[y][!f] = ch[x][f];
			if(ch[y][!f])	pre[ch[y][!f]] = y;
			push_up(y);
			if(pre[y])	ch[pre[y]][r(pre[y])==y]= x;
			pre[x] = pre[y];
			ch[x][f] = y;
			pre[y] = x;
		}
		
		void splay(int x,int goal)	//将x旋转到以goal节点为父节点 
		{
			push_down(x);
			while(pre[x]!=goal)
			{
				int y = pre[x] , z = pre[pre[x]]; 
				if(z==goal)
				{
					rotate(x,l(y)==x);
				}
				else
				{
					int f = (l(z) == y);
					if(ch[y][!f] == x)
					{
						rotate(y,f);
						rotate(x,f);
					}
					else
					{
						rotate(x,!f);
						rotate(x,f);
					}
				}
			} 
			push_up(x);
			if(goal==0)	root = x;
		}
		
		void rotateTo(int k,int goal)
		{
			int x = root;
			while(true)
			{
				push_down(x);
				int tmp = sz[l(x)] + 1;
				if(k==tmp)	break;
				else if(k<tmp)	x = l(x);
				else
				{
					k -= tmp;
					x = r(x);
				}
			}
			splay(x,goal);
		}
		
		void buildTree(int l,int r,int &rt,int f)
		{
			if(l>r)	return;
			int m = mid(l,r);
			rt = ++tot;
			val[rt] = a[m];
			pre[rt] = f;
			buildTree(l,m-1,l(rt),rt);
			buildTree(m+1,r,r(rt),rt);
			push_up(rt);
		}
		
		void rangeCut(int l,int r,int goal)
		{
			rotateTo(l-1,0);
			rotateTo(r+1,root);
			push_down(r(root));
			int x = l(r(root));	//x子树代表[l,r]区间
			//截取 
			l(r(root)) = 0;	
			pre[x] = 0; 
			push_up(r(root));
			push_up(root);
			rotateTo(goal,0);
			rotateTo(goal+1,root);
			push_down(r(root));
			l(r(root)) = x;
			pre[x] = r(root);
			push_up(r(root));
			push_up(root); 
		}
		
		void rangeFlip(int l,int r)
		{
			rotateTo(l-1,0);
			rotateTo(r+1,root);
			push_down(r(root));
			int x = l(r(root));
			rev[x] ^= 1;		
		}
		
		void dfs(int rt,int &size)
		{
			if(!rt)	return;
			push_down(rt);
			dfs(l(rt),size);
			a[size++] = val[rt];
			dfs(r(rt),size);
		} 
		
		
		/********************/
		int query(int l,int r)
		{
			rotateTo(l-1,0);
			rotateTo(r+1,root);
			return mx[l(r(root))];
		} 
		
		void update(int pos,int c)
		{
			rotateTo(pos,0);
			val[root] = c;
			push_up(root);
		}
		
		LL querySum(int l,int r)
		{
			rotateTo(l-1,0);
			rotateTo(r+1,root);
			return sum[l(r(root))];
		} 
		
		void updateInterval(int l,int r,int c)
		{
			rotateTo(l-1,0);
			rotateTo(r+1,root);
			val[l(r(root))] += c;
			sum[l(r(root))] += c * sz[l(r(root))];
			add[l(r(root))] += c;
		}
		
}spt;

//int main()
//{
//	int n,m;
//	while(~scanf("%d%d",&n,&m) && (n>=0 || m>=0))
//	{
//		spt.init();
//		spt.read(n); 
//		spt.buildTree(1,n+2,spt.root,0);
//		char op[5];
//		int a,b,c;
//		while(m--)
//		{
//			scanf("%s%d%d",op,&a,&b);
//			if(op[0]=='C')
//			{
//				scanf("%d",&c);
//				spt.rangeCut(a+1,b+1,c+1);	//因为哨兵0 多加1
//			}
//			else
//			{
//				spt.rangeFlip(a+1,b+1);
//			}
//		}
//		n = 0;
//		spt.dfs(spt.root,n);	//中序遍历即为序列结果 
//		loop(1,n-1)
//		{
//			if(i!=1)	printf(" ");
//			printf("%d",spt.a[i]);
//		}
//		printf("\n");
//	}
//	return 0;
//}





//int main()
//{
//	int n,m;
//	while(scanf("%d%d",&n,&m) == 2)
//	{
//		spt.init();
//		spt.read(n);
//		spt.buildTree(1,n+2,spt.root,0);
//		char op[2];
//		int a,b;
//		while(m--)
//		{
//			scanf("%s%d%d",op,&a,&b);
//			if(op[0]=='Q')
//			{
//				printf("%d\n",spt.query(a+1,b+1));
//			}
//			else
//			{
//				spt.update(a+1,b);
//			}
//		}
//	}
//	return 0;
//} 



int main()
{
	int n,m;
	while(~scanf("%d%d",&n,&m))
	{
		spt.init();
		spt.read(n);
		spt.buildTree(1,n+2,spt.root,0);
		char op[2];
		int a,b,c;
		while(m--)
		{
			scanf("%s%d%d",op,&a,&b);
			if(op[0] == 'Q')
			{
				printf("%I64d\n",spt.querySum(a+1,b+1));
			}
			else
			{
				scanf("%d",&c);
				spt.updateInterval(a+1,b+1,c);
			}
		}
	}
	return 0;
}


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值