【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;
}

  

原文地址:https://www.cnblogs.com/Delostik/p/2121802.html