Splay树(插入、删除、区间最大字段和)—— SPOJ - GSS6 Can you answer these queries VI

对应题目:点击打开链接

SPOJ - GSS6
Time Limit: 298MS Memory Limit: 1572864KB 64bit IO Format: %lld & %llu

 Status

Description

Given a sequence A of N (N <= 100000) integers, you have to apply Q (Q <= 100000) operations:

Insert, delete, replace an element, find the maximum contiguous(non empty) sum in a given interval.

Input

The first line of the input contains an integer N.
The following line contains N integers, representing the starting
sequence A1..AN, (|Ai| <= 10000).

The third line contains an integer Q. The next Q lines contains the operations in following form:

I x y: insert element y at position x (between x - 1 and x).
D x  : delete the element at position x.
R x y: replace element at position x with y.
Q x y: print max{Ai + Ai+1 + .. + Aj | x <= i <= j <= y}.

All given positions are valid, and given values are between -10000 and +10000.

The sequence will never be empty.

Output

For each "Q" operation, print an integer(one per line) as described above.

Example

Input:
5
3 -4 3 -1 6
10
I 6 2
Q 3 5
R 5 -4
Q 3 5
D 2
Q 1 5
I 2 -10
Q 1 6
R 2 -1
Q 1 6

Output:
8
3
6
3
5

题意:

开始有n个数,位置从1到n,

(I  a,  b) 表示在a位置插入数值b,

(D   a) 表示把a位置的数删掉,

(R  a,  b) 表示把a位置的数换成数值b

(Q  a,  b) 表示求a位置到b位置之间的最大连续字段和


思路:

伸展树基本操作,结点信息有子树和sum,  前缀最大连续和lsum,  后缀最大连续和rsum,  子树最大连续和msum。主要是在push_up()的地方要注意下,认真仔细。


数组型:

#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <iostream>
#define MAX(x, y) ((x)>(y)?(x):(y))
const int MAXN=200020;
using namespace std;

struct SplayTree
{
	int val[MAXN];
	int c[MAXN>>1];
	int sz[MAXN];
	int Left[MAXN];
	int Right[MAXN];
	int fa[MAXN];
	int msum[MAXN];
	int lsum[MAXN];
	int rsum[MAXN];
	int sum[MAXN];
	int rt, Size, nil, inf;

	SplayTree()
	{
		rt = Size = nil = 0;
		inf = 1000000000;
	}

	inline void Push_up(int T)
	{
		sz[T] = sz[Left[T]] + sz[Right[T]] + 1;
		sum[T] = sum[Left[T]] + sum[Right[T]] + val[T];
		msum[T] = lsum[T] = rsum[T] = val[T];
		lsum[T] = MAX(lsum[Left[T]], sum[Left[T]] + val[T] + MAX(lsum[Right[T]], 0));
		rsum[T] = MAX(rsum[Right[T]], sum[Right[T]] + val[T] + MAX(rsum[Left[T]], 0));
		msum[T] = MAX(MAX(msum[Left[T]], msum[Right[T]]), val[T] + MAX(lsum[Right[T]], 0) + MAX(rsum[Left[T]], 0));
	}

	void R_rotate(int x)  
	{  
		int y = fa[x];  
		int z = fa[y];  
		int k = Right[x];  
		Left[y] = k;  
		Right[x] = y;  
		if(nil != z){  
			if(y == Left[z]) Left[z] = x;  
			else Right[z] = x;  
		}  
		if(nil != k) fa[k] = y;  
		fa[y] = x;  
		fa[x] = z;  
		Push_up(y);
	}  
	  
	void L_rotate(int x)  
	{  
		int y = fa[x];  
		int z = fa[y];  
		int k = Left[x];  
		Right[y] = k;  
		Left[x] = y;  
		if(nil != z){  
			if(y == Right[z]) Right[z] = x;  
			else Left[z] = x;  
		}  
		if(nil != k) fa[k] = y;  
		fa[y] = x;  
		fa[x] = z;  
		Push_up(y);
	}  

	int FindTag(int x)  
	{  
		if(nil == rt) return nil;  
		int p = rt;  
		int sum = sz[Left[p]] + 1;  
		while(sum != x)  
		{  
			if(sum < x){  
				p = Right[p];  
				x -= sum;  
			}  
			else p = Left[p];  
			if(nil == p) break;
			sum = sz[Left[p]] + 1;  
		}  
		return p;  
	}  
	
	void Splay(int x, int &T)  
	{  
		int p, end;  
		end = fa[T];  
		while(end != fa[x])  
		{  
			p = fa[x];  
			if(end == fa[p]){ //p是根结点  
				if(x == Left[p]) R_rotate(x);  
				else L_rotate(x);  
				break;  
			}  
			//p不是根结点  
			if(x == Left[p]){  
				if(p == Left[fa[p]]){  
					R_rotate(p); //LL  
					R_rotate(x); //LL  
				}  
				else{  
					R_rotate(x); //RL  
					L_rotate(x);  
				}  
			}  
			else{  
				if(p == Right[fa[p]]){ //RR  
					L_rotate(p);  
					L_rotate(x);  
				}  
				else{ //LR  
					L_rotate(x);  
					R_rotate(x);  
				}  
			}  
		}  
		T = x;  
		Push_up(T);
	}  

	inline void NewNode(int pre, int &T, int v)
	{
		T = ++ Size;
		fa[T] = pre;
		sz[T] = 1;
		Left[T] = Right[T] = nil;
		sum[T] = msum[T] = lsum[T] = rsum[T] = val[T] = v;
	}

	void MakeTree(int &T, int pre, int x, int y)
	{
		if(x > y) return;
		int mid = ((x + y)>>1);
		NewNode(pre, T, c[mid]);
		MakeTree(Left[T], T, x, mid - 1);
		MakeTree(Right[T], T, mid + 1, y);
		Push_up(T);
	}
		
	void Init(int n)
	{
		Left[0] = Right[0] = fa[0] = nil;
		sum[0] = 0;
		msum[0] = lsum[0] = rsum[0] = -inf;
		Size = 0;
		NewNode(nil, rt, -inf);
		NewNode(rt, Right[rt], inf);
		sz[rt] = 2;
		fa[rt] = 0;
		fa[rt] = nil;
		fa[Right[rt]] = rt;
		int i;
		for(i = 0; i < n; i++) scanf("%d", c + i);
		MakeTree(Left[Right[rt]], Right[rt], 0, n - 1);
		Push_up(Right[rt]);
		Push_up(rt);
	}

	void Insert(int pos, int v)
	{
		int t;
		t = FindTag(pos);
		Splay(t, rt);
		t = FindTag(pos + 1);
		Splay(t, Right[rt]);
		NewNode(Right[rt], Left[Right[rt]], v);
		Push_up(Right[rt]);
		Push_up(rt);
	}

	void Delete(int pos)
	{
		int t;
		t = FindTag(pos);
		Splay(t, rt);
		t = FindTag(pos + 2);
		Splay(t, Right[rt]);
		Left[Right[rt]] = nil;
		Push_up(Right[rt]);
		Push_up(rt);
	}

	void Replace(int pos, int v)
	{
		int t = FindTag(pos + 1);
		Splay(t, rt);
		if(val[rt] != v){ //值不同才需要更新
			val[rt] = v;
			Push_up(rt);
		}
	}

	void Query(int x, int y)
	{
		int t;
		t = FindTag(x);
		Splay(t, rt);
		t = FindTag(y + 2);
		Splay(t, Right[rt]);
		printf("%d\n", msum[Left[Right[rt]]]);
	}
};

SplayTree spl;

int main()
{
	//freopen("in.txt","r",stdin);
	int n, m, a, b;
	char ord[3];
	while(scanf("%d", &n) == 1)
	{
		spl.Init(n);
		scanf("%d", &m);
		while(m--)
		{
			scanf("%s", ord);
			if('I' == ord[0]){
				scanf("%d%d", &a, &b);
				spl.Insert(a, b);
			}
			else if('D' == ord[0]){
				scanf("%d", &a);
				spl.Delete(a);
			}
			else if('R' == ord[0]){
				scanf("%d%d", &a, &b);
				spl.Replace(a, b);
			}
			else{
				scanf("%d%d", &a, &b);
				spl.Query(a, b);
			}
		}
	}
	return 0;
}


指针型:

#include <cstdio>
#include <cstdlib>
#include <string>
#include <string.h>
#include <cmath>
#include <iostream>
#define MAX(x, y) ((x)>(y)?(x):(y))
const int MAXN = 100010;
using namespace std;
typedef int Type;

typedef struct TREE
{
	Type val;
    Type sum; //以该结点为根的树的元素和
    Type lsum; //以该结点为根的区间从左往右的最大连续和
    Type rsum; //以该结点为根的区间从右往左的最大连续和
    Type msum; //以该结点为根的区间的最大连续和
    TREE *fa, *l, *r;
    int sz; //以该结点为根的树的总结点数
}Tree;

struct SplayTree
{
	public:
	SplayTree()
	{
		rt = NULL;
		Size = 0;
		inf = 1000000000;
		memset(c, 0, sizeof(c));
	}

	~SplayTree()
	{
		FreeTree(rt);
	}

	void Push_up(Tree *T)
	{
		T->sz = (T->l ? T->l->sz : 0) + (T->r ? T->r->sz : 0) + 1;
		T->sum = T->val + (T->l ? T->l->sum : 0) +
			(T->r ? T->r->sum : 0);
		T->msum = T->lsum = T->rsum = T->val;
		Type t;
		if(T->l && T->r){
			T->lsum = MAX(T->l->lsum, T->l->sum + T->val + MAX(T->r->lsum, 0));
			T->rsum = MAX(T->r->rsum, T->r->sum + T->val + MAX(T->l->rsum, 0));
			T->msum = MAX(MAX(T->l->msum, T->r->msum), T->val + MAX(T->r->lsum, 0) + MAX(T->l->rsum, 0));
		}
		else if(T->l)
		{
			T->lsum = MAX(T->l->lsum, T->l->sum + T->val);
			T->rsum = MAX(T->l->rsum, 0) + T->val;
			T->msum = MAX(T->l->msum, T->rsum);
		}
		else if(T->r)
		{
			T->rsum = MAX(T->r->rsum, T->r->sum + T->val);
			T->lsum = MAX(T->r->lsum, 0) + T->val;
			T->msum = MAX(T->r->msum, T->lsum);
		}
	}

	void NewNode(Tree *pre, Tree *&T, Type v)
	{
		T = (Tree *)malloc(sizeof(Tree));
		T->sum = T->msum = T->lsum = T->rsum = T->val = v;
		T->sz = 1;
		T->fa = pre;
		T->l = T->r = NULL;
	}

	void MakeTree(Tree *&T, Tree *pre, int x, int y)
	{
		if(x > y) return;
		int mid = ((x + y)>>1);
		NewNode(pre, T, c[mid]);
		MakeTree(T->l, T, x, mid - 1);
		MakeTree(T->r, T, mid + 1, y);
		Push_up(T);
	}

	void Init(int n)
	{
		Size = n;
		NewNode(NULL, rt, -inf);
		NewNode(rt, rt->r, inf);
		rt->sz = 2;
		rt->r->fa = rt;
		int i;
		for(i = 0; i < n; i++)
			scanf("%d", c + i);
		MakeTree(rt->r->l, rt->r, 0, n - 1);
		Push_up(rt->r);
		Push_up(rt);
	}

	void R_rotate(Tree *x)
	{
		Tree *y = x->fa;
		Tree *z = y->fa;
		Tree *k = x->r;
		y->l = k;
		x->r = y;
		if(z){
			if(y == z->l) z->l = x;
			else z->r = x;
		}
		if(k) k->fa = y;
		y->fa = x;
		x->fa = z;
		Push_up(y);
	}

	void L_rotate(Tree *x)
	{
		Tree *y = x->fa;
		Tree *z = y->fa;
		Tree *k = x->l;
		y->r = k;
		x->l = y;
		if(z){
			if(y == z->r) z->r = x;
			else z->l = x;
		}
		if(k) k->fa = y;
		y->fa = x;
		x->fa = z;
		Push_up(y);
	}
	
	//寻找第x个数的结点
	Tree *FindTag(int x)
	{
		if(NULL == rt) return NULL;
		Tree *p;
		p = rt;
		Type sum = (p->l ? p->l->sz : 0) + 1;
		while(sum != x)
		{
			if(sum < x){
				p = p->r;
				x -= sum;
			}
			else p = p->l;
			if(NULL == p) break;
			sum = (p->l ? p->l->sz : 0) + 1;
		}
		return p;
	}

	void Splay(Tree *X, Tree *&T)
	{
		Tree *p, *end;
		end = T->fa;
		while(X->fa != end)
		{
			p = X->fa;
			if(end == p->fa){ //p是根结点
				if(X == p->l) R_rotate(X);
				else L_rotate(X);
				break;
			}
			//p不是根结点
			if(X == p->l){
				if(p == p->fa->l){
					R_rotate(p); //LL
					R_rotate(X); //LL
				}
				else{
					R_rotate(X); //RL
					L_rotate(X);
				}
			}
			else{
				if(p == p->fa->r){ //RR
					L_rotate(p);
					L_rotate(X);
				}
				else{ //LR
					L_rotate(X);
					R_rotate(X);
				}
			}
		}
		T = X;
		Push_up(T);
	}
		
	void Insert(int pos, Type v)
	{
		Tree *t = FindTag(pos);
		Splay(t, rt);
		t = FindTag(pos + 1);
		Splay(t, rt->r);
		NewNode(rt->r, rt->r->l, v);
		Push_up(rt->r);
		Size++;
	}

	void Delete(int pos)
	{
		if(NULL == rt) return;  
		Tree *t;
		t = FindTag(pos);
		Splay(t, rt);
		t = FindTag(pos + 2);
		Splay(t, rt->r);
		free(rt->r->l);
		rt->r->l = NULL;
		Push_up(rt->r);
		Push_up(rt);
		Size--;
	}

	void Replace(int pos, Type v)
	{
		Tree *t = FindTag(pos + 1);
		Splay(t, rt);
		if(rt->val != v){ //值不同才需要更新
			rt->val = v;
			Push_up(rt);
		}
	}

	void Query(int x, int y)
	{
		Tree *t;
		t = FindTag(x);
		Splay(t, rt);
		t = FindTag(y + 2);
		Splay(t, rt->r);
		printf("%d\n", rt->r->l->msum);
	}

	void FreeTree(Tree *T)
	{
		if(NULL == T) return;
		FreeTree(T->l);
		FreeTree(T->r);
		free(T);
	}
	private:
	Type c[MAXN], inf;
	Tree *rt;
	int Size;
};

SplayTree spl;

int main()
{
	//freopen("in.txt","r",stdin);
	int n, m;
	Type a, b;
	char ord[3];
	while(scanf("%d", &n) == 1)
	{
		spl.Init(n);
		scanf("%d", &m);
		while(m--)
		{
			scanf("%s", ord);
			if('I' == ord[0]){
				scanf("%d%d", &a, &b);
				spl.Insert(a, b);
			}
			else if('D' == ord[0]){
				scanf("%d", &a);
				spl.Delete(a);
			}
			else if('R' == ord[0]){
				scanf("%d%d", &a, &b);
				spl.Replace(a, b);
			}
			else{
				scanf("%d%d", &a, &b);
				spl.Query(a, b);
			}
		}
	}
	return 0;
}











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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值