bzoj 1500: [NOI2005]维修数列(splay)

来源:互联网 发布:东三环java培训 编辑:程序博客网 时间:2024/05/02 02:29

1500: [NOI2005]维修数列

Time Limit: 10 Sec  Memory Limit: 64 MB
Submit: 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

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

Sample Output

-1
10
1
10

HINT

Source

[Submit][Status][Discuss]


题解: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 1000000using 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);}}}


0 0