1500: [NOI2005]維修數列
Time Limit: 10 Sec Memory Limit: 64 MBSubmit: 8379 Solved: 2521
[Submit][Status][Discuss]
Description
Input
輸入文件的第1行包含兩個數N和M,N表示初始時數列中數的個數,M表示要進行的操作數目。第2行包含N個數字,描述初始時的數列。以下M行,每行一條命令,格式參見問題描述中的表格。
Output
對於輸入數據中的GET-SUM和MAX-SUM操作,向輸出文件依次打印結果,每個答案(數字)佔一行。
Sample Input
2 -6 3 5 1 -5 -3 6 3
GET-SUM 5 4
MAX-SUM
INSERT 8 3 -5 7 2
DELETE 12 1
MAKE-SAME 3 3 2
REVERSE 3 6
GET-SUM 5 4
MAX-SUM
Sample Output
10
1
10
HINT
Source
題解:要操作區間 [ L,R ] 。把第L-1個點伸展的根,把第R+1個點伸展到根下面,那麼第R+1個點的左子樹就是區間[ L , R ] 。跟線段樹區間操作類似,對區間打上延時標記即可。
對於插入操作來說,先將插入序列建成一個完全二叉樹,然後再插入對應位置即可
對於刪除操作來說,先將對應區間伸展出來,刪除即可
對於詢問區間和,我們維護每個子樹的和
對於詢問最大連續子區間來說,我們還要維護區間的以做端點爲起點的最大連續和,以右端點爲起點的最大連續和,已經區間最大連續和。
詳情和參加論文:運用伸展樹解決數列維護問題
代碼如下:
#include<stdio.h>
#include<algorithm>
#include<iostream>
#include<string.h>
#include<string>
typedef long long LL;
const int inf=0x3fffffff;
const int nn=210000;
using namespace std;
struct node
{
int val;
int cnt;
LL sum;
LL asum,lsum,rsum;
int xg;
bool fz;
node* pre;
node* ch[2];
}*root;
void fz(node* o)
{
swap(o->ch[0],o->ch[1]);
swap(o->lsum,o->rsum);
}
void fg(node* o,LL val)
{
o->val=val;
o->sum=val*o->cnt;
if(val>0)
o->asum=o->lsum=o->rsum=o->sum;
else
o->asum=o->lsum=o->rsum=val;
}
void push_down(node* o)
{
if(o==NULL)
return ;
if(o->xg!=inf)
{
if(o->ch[0]!=NULL)
{
o->ch[0]->xg=o->xg;
fg(o->ch[0],o->xg);
}
if(o->ch[1]!=NULL)
{
o->ch[1]->xg=o->xg;
fg(o->ch[1],o->xg);
}
o->xg=inf;
}
if(o->fz)
{
if(o->ch[0]!=NULL)
{
o->ch[0]->fz=!o->ch[0]->fz;
fz(o->ch[0]);
}
if(o->ch[1]!=NULL)
{
o->ch[1]->fz=!o->ch[1]->fz;
fz(o->ch[1]);
}
o->fz=false;
}
}
void push_up(node* o)
{
if(o==NULL)
return ;
push_down(o);
o->cnt=1;
o->sum=o->val;
if(o->ch[0]!=NULL)
{
o->cnt+=o->ch[0]->cnt;
o->sum+=o->ch[0]->sum;
}
if(o->ch[1]!=NULL)
{
o->cnt+=o->ch[1]->cnt;
o->sum+=o->ch[1]->sum;
}
if(o->ch[0]!=NULL&&o->ch[1]!=NULL)
{
o->asum=max(o->ch[0]->asum,o->ch[1]->asum);
o->asum=max(o->asum,(LL)o->val);
o->asum=max(o->asum,o->ch[0]->rsum+o->val);
o->asum=max(o->asum,o->ch[1]->lsum+o->val);
o->asum=max(o->asum,o->ch[0]->rsum+o->val+o->ch[1]->lsum);
o->lsum=max(o->ch[0]->lsum,o->ch[0]->sum+o->val);
o->lsum=max(o->lsum,o->ch[0]->sum+o->val+o->ch[1]->lsum);
o->rsum=max(o->ch[1]->rsum,o->ch[1]->sum+o->val);
o->rsum=max(o->rsum,o->ch[1]->sum+o->val+o->ch[0]->rsum);
}
else if(o->ch[0]!=NULL&&o->ch[1]==NULL)
{
o->asum=max(o->ch[0]->asum,(LL)o->val);
o->asum=max(o->asum,o->val+o->ch[0]->rsum);
o->lsum=max(o->ch[0]->lsum,o->ch[0]->sum+o->val);
o->rsum=max((LL)o->val,o->val+o->ch[0]->rsum);
}
else if(o->ch[0]==NULL&&o->ch[1]!=NULL)
{
o->asum=max(o->ch[1]->asum,(LL)o->val);
o->asum=max(o->asum,o->val+o->ch[1]->lsum);
o->lsum=max((LL)o->val,o->val+o->ch[1]->lsum);
o->rsum=max(o->ch[1]->rsum,o->val+o->ch[1]->sum);
}
else
o->asum=o->lsum=o->rsum=o->val;
}
void Rotate(node* o)
{
node* tem=o->pre;
push_down(tem);
push_down(o);
int d;
if(tem->ch[0]==o) d=0;
else d=1;
tem->ch[d]=o->ch[d^1];
if(o->ch[d^1]!=NULL)
o->ch[d^1]->pre=tem;
if(tem->pre!=NULL)
{
if(tem->pre->ch[0]==tem)
tem->pre->ch[0]=o;
else
tem->pre->ch[1]=o;
}
o->pre=tem->pre;
o->ch[d^1]=tem;
tem->pre=o;
push_up(tem);
}
void Splay(node* o,node* f)
{
node* x;
node* y;
int d1,d2;
while(o->pre!=f)
{
if(o->pre->pre==f)
Rotate(o);
else
{
x=o->pre;
y=x->pre;
if(y->ch[0]==x) d1=0;
else d1=1;
if(x->ch[0]==o) d2=0;
else d2=1;
if(d1==d2)
{
Rotate(x);
Rotate(o);
}
else
{
Rotate(o);
Rotate(o);
}
}
}
push_up(o);
if(f==NULL)
root=o;
}
node* select(node* o,int k,node* f)
{
push_down(o);
int tem=0;
if(o->ch[0]!=NULL)
{
tem+=o->ch[0]->cnt;
}
if(tem>=k)
return select(o->ch[0],k,f);
else if(tem+1==k)
{
Splay(o,f);
return o;
}
else
return select(o->ch[1],k-tem-1,f);
}
node* build(node* pre,int *a,int l,int r)
{
node* re;
re=new node;
int mid=(l+r)/2;
re->val=a[mid];
re->pre=pre;
re->fz=false;
re->xg=inf;
re->ch[0]=re->ch[1]=NULL;
if(l==r)
{
push_up(re);
return re;
}
if(l<=mid-1)
re->ch[0]=build(re,a,l,mid-1);
re->ch[1]=build(re,a,mid+1,r);
push_up(re);
return re;
}
void Clear(node* &o)
{
if(o==NULL)
return ;
Clear(o->ch[0]);
Clear(o->ch[1]);
delete o;
o=NULL;
}
void Insert(int L,int R,int *a,int l,int r)
{
node* x=select(root,L,NULL);
node* y=select(root,R,x);
push_down(y);
y->ch[0]=build(y,a,l,r);
Splay(y->ch[0],NULL);
}
void Remove(int L,int R)
{
node* x=select(root,L-1,NULL);
node* y=select(root,R+1,x);
push_down(y);
Clear(y->ch[0]);
Splay(y,NULL);
}
void Change(int L,int R,int c)
{
node* x=select(root,L-1,NULL);
node* y=select(root,R+1,x);
push_down(y);
y->ch[0]->xg=c;
fg(y->ch[0],c);
Splay(y->ch[0],NULL);
}
void Fanzhuan(int L,int R)
{
node* x=select(root,L-1,NULL);
node* y=select(root,R+1,x);
push_down(y);
y->ch[0]->fz=!y->ch[0]->fz;
fz(y->ch[0]);
Splay(y->ch[0],NULL);
}
LL Getsum(int L,int R)
{
if(L>R)
return 0;
node* x=select(root,L-1,NULL);
node* y=select(root,R+1,x);
push_down(y);
return y->ch[0]->sum;
}
LL Getsum2(int L,int R)
{
if(L>R)
return 0;
node* x=select(root,L-1,NULL);
node* y=select(root,R+1,x);
push_down(y);
return y->ch[0]->asum;
}
int n,m;
int a[nn];
void init()
{
root=NULL;
root=new node;
root->fz=false;
root->xg=inf;
root->val=0;
root->cnt=2;
root->pre=NULL;
root->asum=root->sum=root->lsum=root->rsum=0;
root->ch[0]=NULL;
root->ch[1]=NULL;
root->ch[1]=new node;
root->ch[1]->val=0;
root->ch[1]->cnt=1;
root->ch[1]->asum=root->ch[1]->lsum=root->ch[1]->rsum=root->ch[1]->sum=0;
root->ch[1]->pre=root;
root->ch[1]->fz=false;
root->ch[1]->xg=inf;
root->ch[1]->ch[0]=root->ch[1]->ch[1]=NULL;
}
int main()
{
int i;
char s[10];
while(scanf("%d%d",&n,&m)!=EOF)
{
init();
for(i=1;i<=n;i++)
{
scanf("%d",&a[i]);
}
if(n>=1)
Insert(1,2,a,1,n);
int pos,tot,c;
while(m--)
{
scanf("%s",s);
if(strcmp(s,"INSERT")==0)
{
scanf("%d%d",&pos,&tot);
if(tot==0)
continue;
for(i=1;i<=tot;i++)
{
scanf("%d",&a[i]);
}
Insert(pos+1,pos+2,a,1,tot);
}
else if(strcmp(s,"DELETE")==0)
{
scanf("%d%d",&pos,&tot);
if(tot==0)
continue;
Remove(pos+1,pos+tot);
}
else if(strcmp(s,"MAKE-SAME")==0)
{
scanf("%d%d%d",&pos,&tot,&c);
if(tot==0)
continue;
Change(pos+1,pos+tot,c);
}
else if(strcmp(s,"REVERSE")==0)
{
scanf("%d%d",&pos,&tot);
if(tot==0)
continue;
Fanzhuan(pos+1,pos+tot);
}
else if(strcmp(s,"GET-SUM")==0)
{
scanf("%d%d",&pos,&tot);
printf("%lld\n",Getsum(pos+1,pos+tot));
}
else if(strcmp(s,"MAX-SUM")==0)
{
printf("%lld\n",Getsum2(2,root->cnt-1));
}
}
Clear(root);
}
return 0;
}