1500: [NOI2005]维修数列
Time Limit: 10 Sec Memory Limit: 64 MBSubmit: 12283 Solved: 3884
[ Submit][ Status][ Discuss]
Description
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
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
题解:splay
这道题其实好几个月前就尝试写过,不过当时并没有调出来,然后就弃疗了。
今天重新构思写的,不过还是写了接近4个小时T_T
思路很简单,关键是维护的值很多,有很多需要注意的细节。
注意事项如下:
1、make-same,注意cover数组的值不能为0,因为有可能将一段的值全部赋值成0,让cover在没有值得时候等于极大值即可。
2、mx数组用来存储子树中连续一段的最大值。注意这个变量的初值不能为0,应该是最小值,而且mx[0]=-inf。因为在没有左右子树的情况下会访问到0节点。那么mx数值表示的连续一段的长度不能为0,所以如果当前点为负值且没有左右子树,那么mx应该等于本身的值。
3、注意cover的时候只有有的子树才改变,否则将0节点改变了,会造成不必要的麻烦。
4、find第x个节点的时候要注意下方标记。
5、翻转的时候光交换左右儿子还不够,ls,rs也要对应交换(ls表示左边连续的最大值,rs表示右边连续的最大值,这两个值都可以是0)
6、需要写内存回收,否则会MLE
#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<queue>
#define N 1000003
#define inf 1000000
using namespace std;
int ch[N][2],ls[N],rs[N],sum[N],cover[N],rev[N],key[N],size[N],f[N],mx[N];
int n,m,a[N],cnt[N],tot,root;
queue<int> p;
void clear(int now)
{
sum[now]=ls[now]=rs[now]=ch[now][0]=ch[now][1]=key[now]=size[now]=f[now]=rev[now]=0;
mx[now]=-inf;
cover[now]=inf;
}
void update(int now)
{
sum[now]=sum[ch[now][0]]+sum[ch[now][1]]+key[now];
size[now]=size[ch[now][0]]+size[ch[now][1]]+1;
ls[now]=max(ls[ch[now][0]],key[now]+sum[ch[now][0]]+ls[ch[now][1]]);
rs[now]=max(rs[ch[now][1]],key[now]+sum[ch[now][1]]+rs[ch[now][0]]);
mx[now]=max(max(mx[ch[now][0]],mx[ch[now][1]]),rs[ch[now][0]]+ls[ch[now][1]]+key[now]);
}
int get(int now)
{
return ch[f[now]][1]==now;
}
void change(int now,int x)
{
key[now]=x;
sum[now]=x*size[now];
if (x>=0) ls[now]=rs[now]=mx[now]=sum[now];
else ls[now]=rs[now]=0,mx[now]=key[now];
}
void change1(int now)
{
swap(ch[now][0],ch[now][1]);
swap(ls[now],rs[now]);
}
void pushdown(int now)
{
if (cover[now]!=inf) {
if (ch[now][0]) change(ch[now][0],cover[now]),cover[ch[now][0]]=cover[now];
if (ch[now][1]) change(ch[now][1],cover[now]),cover[ch[now][1]]=cover[now];
cover[now]=inf;
}
if (rev[now]){
change1(ch[now][0]); change1(ch[now][1]);
rev[ch[now][0]]^=1; rev[ch[now][1]]^=1;
rev[now]=0;
}
}
void rotate(int x)
{
int y=f[x]; int z=f[y];
pushdown(y); pushdown(x); int which=get(x);
ch[y][which]=ch[x][which^1]; f[ch[x][which^1]]=y;
ch[x][which^1]=y; f[y]=x; f[x]=z;
if (z) ch[z][ch[z][1]==y]=x;
update(y); update(x);
}
void splay(int x,int tar)
{
for (int fa;(fa=f[x])!=tar;rotate(x))
if (f[fa]!=tar) rotate(get(x)==get(fa)?fa:x);
if (!tar) root=x;
}
int build(int l,int r,int fa)
{
if (l>r) return 0;
int now=cnt[++tot]; int mid=(l+r)/2;
key[now]=a[mid]; f[now]=fa;
if (l==r) {
size[now]=1; cover[now]=inf;
if (a[l]>=0) ls[now]=rs[now]=mx[now]=a[mid];
else ls[now]=rs[now]=0,mx[now]=a[mid];
sum[now]=a[mid];
return now;
}
ch[now][0]=build(l,mid-1,now);
ch[now][1]=build(mid+1,r,now);
cover[now]=inf;
update(now);
return now;
}
void dfs(int now)
{
if (!now) return;
dfs(ch[now][1]); dfs(ch[now][0]);
clear(now);
p.push(now);
}
int find(int x)
{
int now=root;
while (true)
{
pushdown(now);
if (x<=size[ch[now][0]])
now=ch[now][0];
else
{
x-=(size[ch[now][0]]+1);
if (x==0) return now;
now=ch[now][1];
}
}
return -1;
}
int main()
{
freopen("a.in","r",stdin);
scanf("%d%d",&n,&m);
a[1]=-1001;a[n+2]=-1001;mx[0]=-inf;
for (int i=2;i<=n+1;i++) scanf("%d",&a[i]);
for (int i=1;i<=1000000;i++) p.push(i);
for (int i=1;i<=n+2;i++) cnt[i]=p.front(),p.pop();
//for (int i=1;i<=n+2;i++) cout<<a[i]<<" ";
//cout<<endl;
root=build(1,n+2,0);
for (int i=1;i<=m;i++) {
char s[20]; scanf("%s",s+1);
if (s[1]=='I') {
int x,k; scanf("%d%d",&x,&k); tot=0;
for (int j=1;j<=k;j++) scanf("%d",&a[j]),cnt[j]=p.front(),p.pop();
int point=build(1,k,0);
int aa=find(x+1); splay(aa,0);
int bb=find(x+2); splay(bb,aa);
ch[ch[root][1]][0]=point;
f[point]=ch[root][1];
update(ch[root][1]);
update(root);
}
if (s[1]=='R') {
int x,k; scanf("%d%d",&x,&k);
k+=x-1;
int aa=find(x); splay(aa,0);
int bb=find(k+2); splay(bb,aa);
int t=ch[ch[root][1]][0];
swap(ch[t][0],ch[t][1]); swap(ls[t],rs[t]);
rev[ch[ch[root][1]][0]]^=1;
update(ch[root][1]); update(root);
}
if (s[1]=='G') {
int x,k; scanf("%d%d",&x,&k);
k+=x-1;
int aa=find(x);
splay(aa,0);
int bb=find(k+2);
splay(bb,aa);
printf("%d\n",sum[ch[ch[root][1]][0]]);
}
if (s[1]=='M'&&s[3]=='K') {
int x,k,c; scanf("%d%d%d",&x,&k,&c);
k+=x-1;
int aa=find(x); splay(aa,0);
int bb=find(k+2); splay(bb,aa);
int t=ch[ch[root][1]][0];
cover[t]=c; change(t,c); update(ch[root][1]); update(root);
}
if (s[1]=='M'&&s[3]=='X') printf("%d\n",mx[root]);
if (s[1]=='D') {
int x,k; scanf("%d%d",&x,&k);
k+=x-1;
int aa=find(x); splay(aa,0);
int bb=find(k+2); splay(bb,aa);
int t=ch[ch[root][1]][0];
dfs(t);
ch[ch[root][1]][0]=0;
update(ch[root][1]); update(root);
}
}
}