1500: [NOI2005]维修数列
Time Limit: 10 Sec Memory Limit: 64 MBSubmit: 16199 Solved: 5391
Description
请写一个程序,要求维护一个数列,支持以下 6 种操作:
请注意,格式栏 中的下划线‘ _ ’表示实际输入文件中的空格
Input
输入的第1 行包含两个数N 和M(M ≤20 000),N 表示初始时数列中数的个数,M表示要进行的操作数目。
第2行包含N个数字,描述初始时的数列。
以下M行,每行一条命令,格式参见问题描述中的表格。
任何时刻数列中最多含有500 000个数,数列中任何一个数字均在[-1 000, 1 000]内。
插入的数字总数不超过4 000 000个,输入文件大小不超过20MBytes。
Output
对于输入数据中的GET-SUM和MAX-SUM操作,向输出文件依次打印结果,每个答案(数字)占一行。
Sample Input
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
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
-1
10
1
10
10
1
10
思路&&分析
这道题很显然也是一个平衡树题,我依旧是用无旋Treap做的,不过要注意这题内存限制只有64M,所以我们不能直接开400W个节点。又因为题目说过任何时刻数列中不会有超过50W个数,所以我们可以开50W个节点,然后进行节点回收。还需要注意的是Pushdown和修改的时候要注意一下小细节的部分,比如在Pushup时要判断他是否有两个孩子,否则就会默认把节点0认为孩子,这样是会挂的……(我就是因为这样在luogu上WA90了好几发)。
Code
#pragma GCC optimize(3)
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
bool Finish_read;
template<class T>inline void read(T &x){Finish_read=0;x=0;int f=1;char ch=getchar();while(!isdigit(ch)){if(ch=='-')f=-1;if(ch==EOF)return;ch=getchar();}while(isdigit(ch))x=x*10+ch-'0',ch=getchar();x*=f;Finish_read=1;}
template<class T>inline void print(T x){if(x/10!=0)print(x/10);putchar(x%10+'0');}
template<class T>inline void writeln(T x){if(x<0)putchar('-');x=abs(x);print(x);putchar('\n');}
template<class T>inline void write(T x){if(x<0)putchar('-');x=abs(x);print(x);}
/*================Header Template==============*/
const int base=48271,maxn=500010;
int seed=233,cnt,rec[maxn],tp,stk[maxn],rtp,a[maxn],rt;
inline int Rand() {
return seed=(int)(1ll*seed*base%INT_MAX);
}
inline void Recycle(int x) {
rec[++rtp]=x;
}
struct Treap {
int sz,ls,rs,val,sum,lmx,rmx,rev,cov,fix,mx;
Treap(int _val=0):val(_val){ls=rs=sz=rev=0;sum=lmx=rmx=mx=val;cov=-2333;fix=Rand();}
}tr[maxn];
inline void Clear(int o) {
if(!o)
return;
Clear(tr[o].ls);
Clear(tr[o].rs);
Recycle(o);
}
inline int Newnode(int val) {
int tmp=rtp?rec[rtp--]:++cnt;
tr[tmp]=Treap(val);
tr[tmp].sz=1;
return tmp;
}
inline void Cover(int o,int x) {
tr[o].sum=x*tr[o].sz;
tr[o].val=x;
tr[o].lmx=tr[o].rmx=tr[o].mx=max(tr[o].sum,x);
tr[o].cov=x;
}
inline void Revnode(int o) {
swap(tr[o].ls,tr[o].rs);
swap(tr[o].lmx,tr[o].rmx);
tr[o].rev^=1;
}
inline int Sum(int o) {
return !o?0:tr[o].sum;
}
inline int Sz(int o) {
return !o?0:tr[o].sz;
}
inline int Lmx(int o) {
return !o?-2333:tr[o].lmx;
}
inline int Rmx(int o) {
return !o?-2333:tr[o].rmx;
}
inline int Mx(int o) {
return !o?-2333:tr[o].mx;
}
inline void Pushup(int o) {
if(!o)
return;
tr[o].sz=Sz(tr[o].ls)+1+Sz(tr[o].rs);
tr[o].sum=Sum(tr[o].ls)+tr[o].val+Sum(tr[o].rs);
tr[o].lmx=max(Lmx(tr[o].ls),Sum(tr[o].ls)+tr[o].val+max(Lmx(tr[o].rs),0));
tr[o].rmx=max(Rmx(tr[o].rs),Sum(tr[o].rs)+tr[o].val+max(Rmx(tr[o].ls),0));
tr[o].mx=max(max(0,Rmx(tr[o].ls))+tr[o].val+max(0,Lmx(tr[o].rs)),max(Mx(tr[o].ls),Mx(tr[o].rs)));
}
inline void Pushdown(int o) {
if(!o)
return;
if(tr[o].rev) {
if(tr[o].ls)
Revnode(tr[o].ls);
if(tr[o].rs)
Revnode(tr[o].rs);
tr[o].rev=0;
}
if(tr[o].cov!=-2333) {
if(tr[o].ls)
Cover(tr[o].ls,tr[o].cov);
if(tr[o].rs)
Cover(tr[o].rs,tr[o].cov);
tr[o].cov=-2333;
}
}
inline int Merge(int a,int b) {
if(!a||!b)
return a|b;
Pushdown(a);
Pushdown(b);
if(tr[a].fix<tr[b].fix) {
tr[a].rs=Merge(tr[a].rs,b);
Pushup(a);
return a;
}
else {
tr[b].ls=Merge(a,tr[b].ls);
Pushup(b);
return b;
}
}
inline pair<int,int> Split(int o,int k) {
if(!o)
return make_pair(0,0);
Pushdown(o);
if(Sz(tr[o].ls)==k) {
int pre=tr[o].ls;
tr[o].ls=0;
Pushup(o);
return make_pair(pre,o);
}
if(Sz(tr[o].ls)+1==k) {
int pre=tr[o].rs;
tr[o].rs=0;
Pushup(o);
return make_pair(o,pre);
}
if(Sz(tr[o].ls)>k) {
pair<int,int>tmp=Split(tr[o].ls,k);
tr[o].ls=tmp.second;
Pushup(o);
return make_pair(tmp.first,o);
}
pair<int,int>tmp=Split(tr[o].rs,k-Sz(tr[o].ls)-1);
tr[o].rs=tmp.first;
Pushup(o);
return make_pair(o,tmp.second);
}
inline int Getsum(int o,int l,int r) {
Pushdown(o);
pair<int,int>tmp1=Split(o,r),tmp2=Split(tmp1.first,l-1);
int res=tr[tmp2.second].sum;
rt=Merge(Merge(tmp2.first,tmp2.second),tmp1.second);
return res;
}
inline int Maxsum(int o) {
return tr[o].mx;
}
inline int Build(int *v,int len) {
tp=0;
for(int i=1;i<=len;i++) {
int now=Newnode(v[i]),lst=0;
while(tp&&tr[stk[tp]].fix>tr[now].fix) {
Pushup(stk[tp]);
lst=stk[tp];
stk[tp--]=0;
}
if(tp)
tr[stk[tp]].rs=now;
tr[now].ls=lst;
stk[++tp]=now;
}
while(tp)
Pushup(stk[tp--]);
return stk[1];
}
inline void Insert(int o,int pos,int k) {
Pushdown(o);
for(int i=1;i<=k;i++)
read(a[i]);
int now=Build(a,k);
pair<int,int>tmp=Split(o,pos);
rt=Merge(Merge(tmp.first,now),tmp.second);
}
inline void Delete(int o,int l,int r) {
Pushdown(o);
pair<int,int>tmp1=Split(o,r),tmp2=Split(tmp1.first,l-1);
Clear(tmp2.second);
rt=Merge(tmp2.first,tmp1.second);
}
inline void Makesame(int o,int l,int r,int k) {
Pushdown(o);
pair<int,int>tmp1=Split(o,r),tmp2=Split(tmp1.first,l-1);
Cover(tmp2.second,k);
rt=Merge(Merge(tmp2.first,tmp2.second),tmp1.second);
}
inline void Reverse(int o,int l,int r) {
Pushdown(o);
pair<int,int>tmp1=Split(o,r),tmp2=Split(tmp1.first,l-1);
Revnode(tmp2.second);
rt=Merge(Merge(tmp2.first,tmp2.second),tmp1.second);
}
inline void Print(int o) {
if(!o)
return;
Print(tr[o].ls);
printf("%d ",tr[o].val);
Print(tr[o].rs);
}
int main() {
int n,m;
read(n);read(m);
Insert(rt,0,n);
while(m--) {
char op[100];
scanf("%s",op);
if(op[0]=='G') {
int l,r;
read(l),read(r);
printf("%d\n",Getsum(rt,l,l+r-1));
}
if(op[0]=='I') {
int pos,tot;
read(pos),read(tot);
Insert(rt,pos,tot);
}
if(op[0]=='M') {
if(op[2]=='X')
printf("%d\n",Maxsum(rt));
if(op[2]=='K') {
int pos,tot,c;
read(pos),read(tot),read(c);
Makesame(rt,pos,pos+tot-1,c);
}
}
if(op[0]=='D') {
int pos,tot;
read(pos),read(tot);
Delete(rt,pos,pos+tot-1);
}
if(op[0]=='R') {
int pos,tot;
read(pos),read(tot);
Reverse(rt,pos,pos+tot-1);
}
// puts("=====Check it:=====");
// Print(rt);
}
}