zoukankan      html  css  js  c++  java
  • 【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;
    }
    

      

  • 相关阅读:
    Javascript操作DOM常用API总结
    实用技巧之Visio绘制流程框图
    实用技巧之Visio绘图
    回复《竞赛部的一封信》
    学习之路
    《软件工程》上课精华分享
    《编译原理》上课笔记2
    sql server2008 远程过程调用失败
    《编译原理》上课笔记1
    python的第五天(复习数据类型)
  • 原文地址:https://www.cnblogs.com/Delostik/p/2121802.html
Copyright © 2011-2022 走看看