<题目描述自行搜索……>
为了学习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……
那就是在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;
}