[NOI2005]维护数列
题目描述
请写一个程序,要求维护一个数列,支持以下 6 种操作:(请注意,格式栏 中的下划线‘ _ ’表示实际输入文件中的空格)
输入格式:
输入文件的第 1 行包含两个数 N 和 M,N 表示初始时数列中数的个数,M 表示要进行的操作数目。 第 2 行包含 N 个数字,描述初始时的数列。 以下 M 行,每行一条命令,格式参见问题描述中的表格
输出格式:
对于输入数据中的 GET-SUM 和 MAX-SUM 操作,向输出文件依次打印结 果,每个答案(数字)占一行。
输入样例#1:
9 8 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
输出样例#1:
-1
10
1
10
说明:
你可以认为在任何时刻,数列中至少有 1 个数。
输入数据一定是正确的,即指定位置的数在数列中一定存在。
50%的数据中,任何时刻数列中最多含有 30 000 个数;
100%的数据中,任何时刻数列中最多含有 500 000 个数。
100%的数据中,任何时刻数列中任何一个数字均在[-1 000, 1 000]内。
100%的数据中,M ≤20 000,插入的数字总数不超过 4 000 000 。
题解:
splay模板题,码量巨大,纯属自虐。。。
对于1,2,5操作模板不用说,典型的序列区间处理。
对于操作3,只需要像线段树一样维护一个下放的标记就可以了,每次rotate的时候下放(这里注意由于有把序列置为0的操作,所以不能用标记记录改变的数,可以根据父亲的num来修改)。
对于操作4,也是维护一个标记,下放是转左右儿子,转lmax,rmax,把标记取反。
对于操作6,像线段树中的一样,维护一个max_sum,max_left,max_right,update时注意一下就可以了。
最后注意一下哨兵节点的初始化就可以了。
代码:
#include<cstdio>
#include<iostream>
#include<cstring>
#include<cstdlib>
using namespace std;
const int max_n = 4000001;
const int max_s = 11;
const int inf = 1e6+7;
struct node
{
int num,sum,rank,rev,delta,max_sum,max_left,max_right,wh_ch;
node *ch[2],*fa;
void set_son(node *son,int wh);
int get_wh();
void update();
void pushdown();
void pushrev();
void pushdelta(int now);
}pool[max_n],*null,*root,*temp,*bef,*beh;
inline int node::get_wh()
{
return fa->ch[0]==this ? 0 : 1;
}
inline void node::set_son(node *son,int wh)
{
ch[wh]=son;
if(son!=null) son->fa=this;
update();
}
inline void node::pushrev()
{
swap(ch[0],ch[1]);
swap(max_left,max_right);
rev^=1;
}
inline void node::pushdelta(int now)
{
delta=now;
num=delta;
sum=delta*rank;
max_left=max_right=max_sum=max(sum,now);
wh_ch=1;
}
inline void node::update()
{
sum=ch[0]->sum+num+ch[1]->sum;
rank=ch[0]->rank+1+ch[1]->rank;
max_left=max(max(ch[0]->max_left,ch[0]->sum+num),ch[0]->sum+num+ch[1]->max_left);
max_right=max(max(ch[1]->max_right,ch[1]->sum+num),ch[1]->sum+num+ch[0]->max_right);
max_sum=max(max(ch[0]->max_sum,ch[1]->max_sum),max(num,ch[0]->max_right+num));
max_sum=max(max(max_sum,num+ch[1]->max_left),ch[0]->max_right+num+ch[1]->max_left);
}
inline void node::pushdown()
{
if(rev)
{
if(ch[0]!=null) ch[0]->pushrev();
if(ch[1]!=null) ch[1]->pushrev();
rev=0;
}
if(wh_ch)
{
if(ch[0]!=null) ch[0]->pushdelta(delta);
if(ch[1]!=null) ch[1]->pushdelta(delta);
delta=0; wh_ch=0;
}
update();
}
char s[max_s];
int a[max_n];
int n,m,x,tot;
inline int read()
{
int ans=0;char c;bool flag=false;
while( (c=getchar())==' ' || c=='\n' || c=='\r');
if(c=='-') flag=true;else ans=c-'0';
while((c=getchar()) >='0' && c<='9') ans=ans*10+c-'0';
return ans*(flag?-1:1);
}
inline void init()
{
null=pool;
null->sum=0;
null->rank=0;
null->num=0;
null->wh_ch=0;
null->rev=null->delta=0;
null->max_left=null->max_right=null->max_sum=-inf;
null->fa=null->ch[0]=null->ch[1]=null;
root=null;
}
inline node *newnode(int a)
{
node *now=pool+ ++tot;
now->sum=a;
now->rank=1;
now->num=a;
now->wh_ch=0;
now->rev=now->delta=0;
now->max_left=now->max_right=now->max_sum=a;
now->fa=now->ch[0]=now->ch[1]=null;
return now;
}
inline void rotate(node *now)
{
node *f=now->fa,*grand=now->fa->fa;
if(grand!=null) grand->pushdown();
f->pushdown(); now->pushdown();
int wh=now->get_wh();
f->set_son(now->ch[wh^1],wh);
now->set_son(f,wh^1);
now->fa=grand;
if(grand!=null) grand->ch[grand->ch[0]==f ? 0 : 1]=now;
f->update(); now->update();
if(grand!=null) grand->update();
}
inline void splay(node *now,node *tar)
{
for(; now->fa!=tar; rotate(now))
if(now->fa->fa!=tar)
now->get_wh()==now->fa->get_wh() ? rotate(now->fa) : rotate(now);
if(tar==null) root=now;
}
inline node *build(int l,int r)
{
if(l>r) return null;
int mid=(l+r)>>1;
node *now=newnode(a[mid]);
now->set_son(build(l,mid-1),0);
now->set_son(build(mid+1,r),1);
return now;
}
inline node *find(int k)
{
node *now=root;
while(now!=null)
{
now->pushdown();
if(k==now->rank-now->ch[1]->rank) break;
if(k<now->rank-now->ch[1]->rank) now=now->ch[0];
else k-=now->rank-now->ch[1]->rank,now=now->ch[1];
}
return now;
}
inline void insert()
{
int pos,len;
pos=read();
len=read();
for(int i=1; i<=len; ++i)
a[i]=read();
temp=build(1,len);
node *now=find(pos+1),*last=find(pos+2);
splay(now,null); splay(last,now);
last->set_son(temp,0);
now->update();
}
inline void delet()
{
int pos,len;
pos=read(); len=read();
node *now=find(pos),*maxn=find(pos+len+1);
splay(now,null);
splay(maxn,now);
maxn->set_son(null,0);
root->update();
}
inline void make_same()
{
int pos,len,x;
scanf("%d%d%d",&pos,&len,&x);
node *now=find(pos),*maxn=find(pos+len+1);
splay(now,null); splay(maxn,now);
root->ch[1]->ch[0]->pushdelta(x);
root->ch[1]->update(); root->update();
}
inline void reverse()
{
int pos,len;
scanf("%d%d",&pos,&len);
node *now=find(pos),*maxn=find(pos+len+1);
splay(now,null); splay(maxn,now);
root->ch[1]->ch[0]->pushrev();
root->ch[1]->update(); root->update();
}
inline void get_sum()
{
int pos,len;
scanf("%d%d",&pos,&len);
node *now=find(pos),*maxn=find(pos+len+1);
splay(now,null);
splay(maxn,now);
printf("%d\n",root->ch[1]->ch[0]->sum);
}
inline void max_sum()
{
printf("%d\n",root->max_sum);
}
int main()
{
freopen("seq2005.in","r",stdin);
freopen("seq2005.out","w",stdout);
scanf("%d%d",&n,&m);
init();
a[1]=a[n+2]=-inf;
for(int i=2; i<=n+1; ++i)
a[i]=read();
root=build(1,n+2);
for(int i=1; i<=m; ++i)
{
scanf("%s",s);
if(s[0]=='I') insert();
if(s[0]=='D') delet();
if(s[0]=='M' && s[2]=='K') make_same();
if(s[0]=='R') reverse();
if(s[0]=='G') get_sum();
if(s[0]=='M' && s[2]=='X') max_sum();
}
return 0;
}