【NOI 2005】维修数列 Sequence

  <题目描述自行搜索……>

  为了学习LCT,要练好Splay。这道题的插入、修改、翻转操作都是裸的Splay操作,不怎么难,关键是最大子段和的维护上。之前做过一道线段树的题叫《小白逛公园》,是要用一棵线段树来维护最大子段和,然后我就把线段树的维护方法加到了Splay上,写了一晚上,总算是A掉了……

  维护最大字段和的方法:

  我们先维护一个序列的包括最左端节点的最大子段和MaxStartLeft,维护一个包括其最右端节点的最大字段和MaxStartRight,然后再维护每个节点左子树的Sum和右子树的Sum。那么对于每个节点,以他为根的子树的序列的最大子段和就有如下几种情况:

    1.节点本身

    2.左子树中最大子段和

    3.右子树中最大子段和

    4.左子树的MaxStartRight+节点本身

    5.右子树的MaxStartLeft+节点本身

    6.左子树的MaxStartRight+节点本身+右子树的MaxStartLeft

  然后每次Update的时候维护一下就好了。

  虽然是A了,但是在OJ上是交不过的,因为没有动态释放内存,内存巨大……

#include <iostream>

#include <cstdio>

#include <cstdlib>

#include <cstring>

#include <cmath>

#define NIL SPLAY

#define MN 3000000

using namespace std;

template<class T>inline void gmax(T &a,T b){if(a<b)a=b;}



const int INF=100000;

int n,m,pos,num,x,tmp[500000];

char s[10];

struct SPLAYTREE{

	struct NODE{

		int key,sum,maxsum,mls,mrs,size;

		bool rev,same;

		NODE *left,*right,*father;

		NODE (){}

		NODE(int _key):key(_key){

			maxsum=mrs=mls=sum=key;

			size=1;rev=same=false;

		}

	}SPLAY[MN],*SP,*root,*head,*tail;

	

	void NewNode(NODE *&t,int key){

		t=new(++SP)NODE(key);

		t->left=t->right=t->father=NIL;

	}

	

	void init(){

		SP=NIL;

		NIL->key=NIL->maxsum=NIL->mls=NIL->mrs=-INF,NIL->sum=NIL->size=0;

		NIL->left=NIL->right=NIL->father=NIL;

		NewNode(head,-INF);

		NewNode(tail,-INF);

		head->sum=tail->sum=0;

		head->right=tail,tail->father=head,head->size++;

		root=head;

	}

	

	void pushdown(NODE *&t){

		if(t->rev){

			swap(t->left,t->right);

			swap(t->mls,t->mrs);

			t->left->rev=!t->left->rev,t->right->rev=!t->right->rev;

			t->rev=false;

		}

		if(t->same){

			t->same=false;

			t->left->same=t->right->same=true;

			t->left->key=t->right->key=t->key;

			t->mls=t->mrs=t->sum=t->maxsum=t->key*t->size;

			if(t->key<0) t->mls=t->mrs=t->maxsum=t->key;

		}

	}

	

	void update(NODE *&t){

		t->size=t->left->size+t->right->size+1;

		t->sum=t->left->sum+t->right->sum+t->key;

		t->mls=t->left->mls;

		gmax(t->mls,t->left->sum+t->key);

		gmax(t->mls,t->left->sum+t->key+t->right->mls);

		t->mrs=t->right->mrs;

		gmax(t->mrs,t->right->sum+t->key);

		gmax(t->mrs,t->right->sum+t->key+t->left->mrs);

		t->maxsum=t->key;

		gmax(t->maxsum,t->left->maxsum);

		gmax(t->maxsum,t->right->maxsum);

		gmax(t->maxsum,t->left->mrs+t->key);

		gmax(t->maxsum,t->right->mls+t->key);

		gmax(t->maxsum,t->left->mrs+t->key+t->right->mls);

	}

	

	void zig(NODE *&t){

		NODE *f=t->father,*r=t->right;

		pushdown(f->right);

		pushdown(t->left);

		pushdown(t->right);

		t->father=f->father;

		if(f==root) root=t;

		else{

			if(f->father->left==f) f->father->left=t;

			else f->father->right=t;

		}

		t->right=f,f->father=t,f->left=r,r->father=f;

		update(f);update(t);

	}

	

	void zag(NODE *&t){

		NODE *f=t->father,*l=t->left;

		pushdown(f->left);

		pushdown(t->left);

		pushdown(t->right);

		t->father=f->father;

		if(f==root) root=t;

		else{

			if(f->father->right==f) f->father->right=t;

			else f->father->left=t;

		}

		t->left=f,f->father=t,f->right=l,l->father=f;

		update(f);update(t);

	}

	

	void splay(NODE *&root,NODE *&t){

		pushdown(t);

		while(root!=t){

			if(t->father==root){

				if(t->father->left==t) zig(t);

				else zag(t);

			}else{

				if(t->father->father->left==t->father){

					if(t->father->left==t) zig(t->father),zig(t);

					else zag(t),zig(t);

				}else{

					if(t->father->right==t) zag(t->father),zag(t);

					else zig(t),zag(t);

				}

			}

		}

	}

	

	void select(NODE *&root,int pos){

		NODE *r=root;

		while(pushdown(r),r->left->size+1!=pos){

			if(r->left->size+1>pos) r=r->left;

			else pos-=r->left->size+1,r=r->right;

		}

		splay(root,r);

	}

	

	void insert(int pos,int num){

		NODE *t,*p,*q;

		NewNode(t,tmp[1]);p=q=t;

		for(int i=2;i<=num;i++){

			NewNode(t,tmp[i]);

			t->father=p;

			p=p->right=t;

		}

		select(root,pos);

		select(root->right,1);

		root->right->left=q;

		q->father=root->right;

		splay(root,p);

	}



	void Delete(int pos,int num){

		select(root,pos);

		select(root->right,num+1);

		NODE *t=root->right;

		t->left=NIL;

		splay(root,t);

	}

	

	void Make_Same(int pos,int num,int key){

		select(root,pos);

		select(root->right,num+1);

		NODE *t=root->right->left;

		t->key=key,t->same=true;

		splay(root,t);

	}

	

	void Reverse(int pos,int num){

		select(root,pos);

		select(root->right,num+1);

		NODE *t=root->right->left;

		t->rev=!t->rev;

		splay(root,t);

	}

	

	int Get_Sum(int pos,int num){

		select(root,pos);

		select(root->right,num+1);

		return root->right->left->sum;

	}

	

	void Max_Sum(){printf("%d\n",root->maxsum);}

}tree;



int main(){

	scanf("%d%d",&n,&m);

	tree.init();

	for(int i=1;i<=n;i++) scanf("%d",&tmp[i]);

	tree.insert(1,n);

	while(m--){

		scanf("%s",s);

		switch(s[0]){

			case 'I':

				scanf("%d%d",&pos,&num);

				if(!num) break;

				for(int i=1;i<=num;i++)	scanf("%d",&tmp[i]);

				tree.insert(pos+1,num);

				break;

			case 'D':

				scanf("%d%d",&pos,&num);

				tree.Delete(pos,num);

				break;

			case 'R':

				scanf("%d%d",&pos,&num);

				tree.Reverse(pos,num);

				break;

			case 'G':

				scanf("%d%d",&pos,&num);

				printf("%d\n",tree.Get_Sum(pos,num));

				break;

			case 'M':

				if(s[2]=='K'){

					scanf("%d%d%d",&pos,&num,&x);

					tree.Make_Same(pos,num,x);

					break;

				}else tree.Max_Sum();

		}

	}	

	return 0;

}

  


  然后我发现了一个很神奇的事情,改动程序里的一个小地方能提高我的程序3s……

  pic

  那就是在zig(t)和zag(t)的时候,我们不update(t),而是在splay()中更新t,这样就减少了更新次数……

#include <iostream>

#include <cstdio>

#include <cstdlib>

#include <cstring>

#include <cmath>

#define NIL SPLAY

#define MN 3000000

using namespace std;

template<class T>inline void gmax(T &a,T b){if(a<b)a=b;}



const int INF=100000;

int n,m,pos,num,x,tmp[500000];

char s[10];

struct SPLAYTREE{

	struct NODE{

		int key,sum,maxsum,mls,mrs,size;

		bool rev,same;

		NODE *left,*right,*father;

		NODE (){}

		NODE(int _key):key(_key){

			maxsum=mrs=mls=sum=key;

			size=1;rev=same=false;

		}

	}SPLAY[MN],*SP,*root,*head,*tail;

	

	void NewNode(NODE *&t,int key){

		t=new(++SP)NODE(key);

		t->left=t->right=t->father=NIL;

	}

	

	void init(){

		SP=NIL;

		NIL->key=NIL->maxsum=NIL->mls=NIL->mrs=-INF,NIL->sum=NIL->size=0;

		NIL->left=NIL->right=NIL->father=NIL;

		NewNode(head,-INF);

		NewNode(tail,-INF);

		head->sum=tail->sum=0;

		head->right=tail,tail->father=head,head->size++;

		root=head;

	}

	

	void pushdown(NODE *&t){

		if(t->rev){

			swap(t->left,t->right);

			swap(t->mls,t->mrs);

			t->left->rev=!t->left->rev,t->right->rev=!t->right->rev;

			t->rev=false;

		}

		if(t->same){

			t->same=false;

			t->left->same=t->right->same=true;

			t->left->key=t->right->key=t->key;

			t->mls=t->mrs=t->sum=t->maxsum=t->key*t->size;

			if(t->key<0) t->mls=t->mrs=t->maxsum=t->key;

		}

	}

	

	void update(NODE *&t){

		t->size=t->left->size+t->right->size+1;

		t->sum=t->left->sum+t->right->sum+t->key;

		t->mls=t->left->mls;

		gmax(t->mls,t->left->sum+t->key);

		gmax(t->mls,t->left->sum+t->key+t->right->mls);

		t->mrs=t->right->mrs;

		gmax(t->mrs,t->right->sum+t->key);

		gmax(t->mrs,t->right->sum+t->key+t->left->mrs);

		t->maxsum=t->key;

		gmax(t->maxsum,t->left->maxsum);

		gmax(t->maxsum,t->right->maxsum);

		gmax(t->maxsum,t->left->mrs+t->key);

		gmax(t->maxsum,t->right->mls+t->key);

		gmax(t->maxsum,t->left->mrs+t->key+t->right->mls);

	}

	

	void zig(NODE *&t){

		NODE *f=t->father,*r=t->right;

		pushdown(f->right);

		pushdown(t->left);

		pushdown(t->right);

		t->father=f->father;

		if(f==root) root=t;

		else{

			if(f->father->left==f) f->father->left=t;

			else f->father->right=t;

		}

		t->right=f,f->father=t,f->left=r,r->father=f;

		update(f);

	}

	

	void zag(NODE *&t){

		NODE *f=t->father,*l=t->left;

		pushdown(f->left);

		pushdown(t->left);

		pushdown(t->right);

		t->father=f->father;

		if(f==root) root=t;

		else{

			if(f->father->right==f) f->father->right=t;

			else f->father->left=t;

		}

		t->left=f,f->father=t,f->right=l,l->father=f;

		update(f);

	}

	

	void splay(NODE *&root,NODE *&t){

		pushdown(t);

		while(root!=t){

			if(t->father==root){

				if(t->father->left==t) zig(t);

				else zag(t);

			}else{

				if(t->father->father->left==t->father){

					if(t->father->left==t) zig(t->father),zig(t);

					else zag(t),zig(t);

				}else{

					if(t->father->right==t) zag(t->father),zag(t);

					else zig(t),zag(t);

				}

			}

		}

		update(t);

	}

	

	void select(NODE *&root,int pos){

		NODE *r=root;

		while(pushdown(r),r->left->size+1!=pos){

			if(r->left->size+1>pos) r=r->left;

			else pos-=r->left->size+1,r=r->right;

		}

		splay(root,r);

	}

	

	void insert(int pos,int num){

		NODE *t,*p,*q;

		NewNode(t,tmp[1]);p=q=t;

		for(int i=2;i<=num;i++){

			NewNode(t,tmp[i]);

			t->father=p;

			p=p->right=t;

		}

		select(root,pos);

		select(root->right,1);

		root->right->left=q;

		q->father=root->right;

		splay(root,p);

	}



	void Delete(int pos,int num){

		select(root,pos);

		select(root->right,num+1);

		NODE *t=root->right;

		t->left=NIL;

		splay(root,t);

	}

	

	void Make_Same(int pos,int num,int key){

		select(root,pos);

		select(root->right,num+1);

		NODE *t=root->right->left;

		t->key=key,t->same=true;

		splay(root,t);

	}

	

	void Reverse(int pos,int num){

		select(root,pos);

		select(root->right,num+1);

		NODE *t=root->right->left;

		t->rev=!t->rev;

		splay(root,t);

	}

	

	int Get_Sum(int pos,int num){

		select(root,pos);

		select(root->right,num+1);

		return root->right->left->sum;

	}

	

	void Max_Sum(){printf("%d\n",root->maxsum);}

}tree;



int main(){

	scanf("%d%d",&n,&m);

	tree.init();

	for(int i=1;i<=n;i++) scanf("%d",&tmp[i]);

	tree.insert(1,n);

	while(m--){

		scanf("%s",s);

		switch(s[0]){

			case 'I':

				scanf("%d%d",&pos,&num);

				if(!num) break;

				for(int i=1;i<=num;i++)	scanf("%d",&tmp[i]);

				tree.insert(pos+1,num);

				break;

			case 'D':

				scanf("%d%d",&pos,&num);

				tree.Delete(pos,num);

				break;

			case 'R':

				scanf("%d%d",&pos,&num);

				tree.Reverse(pos,num);

				break;

			case 'G':

				scanf("%d%d",&pos,&num);

				printf("%d\n",tree.Get_Sum(pos,num));

				break;

			case 'M':

				if(s[2]=='K'){

					scanf("%d%d%d",&pos,&num,&x);

					tree.Make_Same(pos,num,x);

					break;

				}else tree.Max_Sum();

		}

	}	

	return 0;

}

  

你可能感兴趣的:(sequence)