刷题总结——维护数列(NOI2005 bzoj1500 splay)

题目:

题目背景

NOI2005 DAY1 T2

题目描述

请写一个程序,要求维护一个数列,支持以下 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 
10 

10

备注

【样例说明】
初始时,我们拥有数列:
2 -6 3 5 1 -5 -3 6 3

执行操作 GET-SUM 5 4 ,表示求出数列中从第 5 个数开始连续 4 个数字之和,如下图中的灰色部分 1+(-5)+(-3)+6 = -1:
2 -6 3 5 1 -5 -3 6 3

执行操作 MAX-SUM ,表示要求求出当前数列中最大的一段和,即如下图所示,应为 3+5+1+(-5)+(-3)+6+3 = 10:
2 -6 3 5 1 -5 -3 6 3

执行操作 INSERT 8 3 -5 7 2,即在数列中第 8 个数字后插入 -5 7 2,如下所示的灰色部分:
2 -6 3 5 1 -5 -3 6 -5 7 2 3

执行操作 DELETE 12 1,表示删除第 12 个数字,即最后一个:
2 -6 3 5 1 -5 -3 6 -5 7 2

执行操作 MAKE-SAME 3 3 2 ,表示从第 3 个数开始的 3 个数字,即下图中的灰色部分,统一修改为 2 :
2 -6 3 5 1 -5 -3 6 -5 7 2
    改为
2 -6 2 2 2 -5 -3 6 -5 7 2

执行操作 REVERSE 3 6,表示取出数列中从第 3 个数开始的连续 6 个数:

如上所示的灰色部分 2 2 2 -5 -3 6 ,翻转后得到 6 -3 -5 2 2 2 ,并放回原来位置:
2 -6 6 -3 -5 2 2 2 -5 7 2

最后执行 GET-SUM 5 4 和 MAX-SUM ,不难得到答案 1 和 10 。

【评分方法】
本题设有部分分,对于每一个测试点:

  • 如果你的程序能在输出文件正确的位置上打印 GET-SUM 操作的答案,你可以得到该测试点 60% 的分数;
  • 如果你的程序能在输出文件正确的位置上打印 MAX-SUM 操作的答案,你可以得到该测试点 40% 的分数;
  • 以上两条的分数可以叠加,即如果你的程序正确输出所有 GET-SUM 和 MAX-SUM 操作的答案,你可以得到该测试点 100% 的分数。

请注意:如果你的程序只能正确处理某一种操作,请确定在输出文件正确的位置上打印结果,即必须为另一种操作留下对应的行,否则我们不保证可以正确评分。

【数据规模和约定】 
你可以认为在任何时刻,数列中至少有 1 个数。
输入数据一定是正确的,即指定位置的数在数列中一定存在。
50% 的数据中,任何时刻数列中最多含有 30,000 个数;
100% 的数据中,任何时刻数列中最多含有 500,000 个数。
100% 的数据中,任何时刻数列中任何一个数字均在 [-1,000,1,000] 内 。 
100% 的数据中,M≤20,000,插入的数字总数不超过 4,000,000 个,输入文件大小不超过 20 MBytes 。

题解:

splay大boss题····能打得来splay操作基本没问题了·····

维护lm,rm,mx,sum,size分别表示包含该节点子树代表的区间的左端点的最大序列和,包含该节点子树代表的区间右端点的最大序列和,totsum:此区间的最大序列和最大值,以及该节点子树的和的总和和该节点子树的大小

然后就是各种提取区间操作了,在此引用Zig_zag题解,%%%%

注:标准结构:区间右端点+1(R)为根,区间左端点-1(L)为根的左儿子,这样目标区间就是L的右儿子,这种形式以后都用"标准结构"代替。

插入操作:先把需要插入的序列建成一个小平衡树(递归),转出标准结构,插到L的右儿子上就行了。

删除操作:转出标准结构,把L的右儿子切下来就行了(注意因为要回收空间,所以还是把要切的子树遍历了一遍,把这颗树上的节点标号入栈)。

覆盖操作:转出标准结构,把L的右儿子打上覆盖标记cov(以后下传的时候把节点的值改为cov的值,sum变为cov*size,la=ra=ma变为cov和sum中较大的一个,因为有负数的情况)

翻转操作:转出标准结构,把L的右儿子打上翻转标记rev(以后下传的时候要交换左右儿子并且交换la和ra)

求和操作:转出标准结构,答案就是L的右儿子的sum

最大值操作:转出标准结构,答案就是L的右儿子的ma

区间操作的时候一定要明白一点,就是打标记的同时做修改,就是说当一个点带了标记的时候,它已经被修改过了。

代码:

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<ctime>
#include<cstring>
#include<string>
#include<algorithm>
#include<cctype>
using namespace std;
const int N=1000005;
const int inf=0x3f3f3f3f;
int ans,n,m,father[N],son[N][2],rev[N],sum[N],lm[N],rm[N],mx[N],cov[N],size[N],key[N],a[N],que[N],tail,tot,st,ed,root;
char s[25];
inline int R()
{ 
  char c;int f=0,i=1;
  for(c=getchar();(c<'0'||c>'9')&&c!='-';c=getchar());
  if(c=='-')  i=-1,c=getchar();
  for(;c<='9'&&c>='0';c=getchar())
    f=(f<<3)+(f<<1)+c-'0';
  return f*i;
}
void update(int x)
{
        if (!x) return;
        lm[x]=max(lm[son[x][0]],sum[son[x][0]]+key[x]+max(0,lm[son[x][1]]));
        rm[x]=max(rm[son[x][1]],sum[son[x][1]]+key[x]+max(0,rm[son[x][0]]));
        mx[x]=max(max(mx[son[x][0]],mx[son[x][1]]),key[x]+max(0,rm[son[x][0]])+max(0,lm[son[x][1]]));
        sum[x]=sum[son[x][0]]+sum[son[x][1]]+key[x];
        size[x]=size[son[x][0]]+size[son[x][1]]+1;
}
inline void reverse(int now)
{
  if(!now)  return;
  swap(son[now][1],son[now][0]);
  swap(lm[now],rm[now]);
  rev[now]^=1;
}
inline void cover(int now,int v)
{
  if(!now)  return;
  sum[now]=size[now]*v;key[now]=cov[now]=v;
  lm[now]=rm[now]=mx[now]=max(sum[now],v);
}
void pushdown(int x)
{
        if (!x) return;
        if (rev[x])
        {
                reverse(son[x][0]);
                reverse(son[x][1]);
                rev[x]=0;
        }
        if (cov[x]!=-inf)
        {
                cover(son[x][0],cov[x]);
                cover(son[x][1],cov[x]);
                cov[x]=-inf;
        }
}
inline int get(int now)
{
  return son[father[now]][1]==now;
}
inline void rotate(int now)
{
  int fa=father[now],ofa=father[fa],which=get(now);
  son[fa][which]=son[now][which^1],father[son[fa][which]]=fa;
  son[now][which^1]=fa,father[fa]=now,father[now]=ofa;
  if(ofa)  son[ofa][son[ofa][1]==fa]=now;
  update(fa),update(now);
}
inline void relax(int now,int to)
{
  if(now!=to)  relax(father[now],to);
  pushdown(now);
}
inline void splay(int now,int to)
{
  relax(now,to);
  while(father[now]!=to)
  {
    if(father[father[now]]!=to)  rotate(get(now)==get(father[now])?father[now]:now);
    rotate(now);
  }
  if(!to)  root=now;
}
inline int pick()
{
  if(tail)  return que[tail--];
  else return ++tot;
}
int produce(int x)
{
        int t=pick();
        key[t]=a[x];
        cov[t]=-inf;
        rev[t]=0;
        lm[t]=rm[t]=mx[t]=-inf;
        return t;
}
inline int find(int now,int k)
{
  pushdown(now);
  if(size[son[now][0]]>=k)  return find(son[now][0],k);  
  else if(size[son[now][0]]+1==k)  return now;
  else return find(son[now][1],k-size[son[now][0]]-1);
}
int build(int l,int r)
{
        int mid=(l+r)>>1,le=0,ri=0;
        if (l<mid)      le=build(l,mid-1);
        int t=produce(mid);
        if (r>mid)      ri=build(mid+1,r);
        if (le)       son[t][0]=le,father[le]=t;
        if (ri)      son[t][1]=ri,father[ri]=t;
        update(t);
        return t;
}
void del(int &x)
{
        if (!x) return;
        que[++tail]=x;
        father[x]=0;
        del(son[x][0]);
        del(son[x][1]);
        lm[x]=rm[x]=mx[x]=-inf;
        x=0;
}
int main()
{
  //freopen("a.in","r",stdin);
  n=R();m=R();a[st=1]=0;a[ed=n+2]=0;
  for(int i=2;i<=n+1;i++)  a[i]=R();
  rm[0]=lm[0]=mx[0]=-inf;
  root=build(1,n+2);int x,y,z,l,r;
  for (int i=1;i<=m;i++)
        {
                scanf("%s",s);
                if (s[0]=='I')
                {
                        x=R(),y=R();
                        l=find(root,x+1); r=find(root,x+2);
                        splay(r,0); splay(l,root);
                        for (int j=1;j<=y;j++) 
                          a[j]=R();
                        int tmp=build(1,y);
                        father[tmp]=l; son[l][1]=tmp;                 
                        update(l); update(r);
                        splay(tmp,root);
                }
                if (s[0]=='D')
                {
                        x=R(),y=R();
                        r=find(root,x+y+1);splay(r,0);
                        l=find(root,x);splay(l,root);
                        del(son[l][1]);
                        update(l); update(r);
                }                       
                if (s[0]=='M'&&s[2]=='K')
                {
                        x=R(),y=R(),z=R();
                        r=find(root,x+y+1);splay(r,0);
                        l=find(root,x);splay(l,root);
                        cover(son[l][1],z);
                }
                if (s[0]=='R')
                {
                        x=R(),y=R();
                        r=find(root,x+y+1);splay(r,0);
                        l=find(root,x);splay(l,root);
                        reverse(son[l][1]);
                }
                if (s[0]=='G')
                {
                        x=R(),y=R();
                        r=find(root,x+y+1);splay(r,0);
                        l=find(root,x);splay(l,root);
                        ans=sum[son[l][1]];
                        printf("%d\n",ans);
                }
                if (s[0]=='M'&&s[2]=='X')
                {
                        splay(ed,0); splay(st,root);
                        ans=mx[son[st][1]];
                        printf("%d\n",ans);
                }
        }
  return 0;
}

 

posted @ 2017-09-29 08:16  AseanA  阅读(245)  评论(0编辑  收藏  举报