zoukankan      html  css  js  c++  java
  • [NOI2005]维修数列

    Description

    请写一个程序,要求维护一个数列,支持以下 6 种操作:

    请注意,格式栏 中的下划线‘ _ ’表示实际输入文件中的空格

    img

    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

    img

    Solution

    传说中的splay大毒瘤题。操作很多,很复杂。在经过三遍重构代码之后,终于拿着和题解相似度高达百分之90的代码过掉了。。。

    那么我们一个一个操作来看。首先是插入,可以发现的是在某个数字后面插入,一般的思想是读进来一个往里插一个进去。这想法没错,但是这个题并不能这么做,具体等一下说。

    然后是删除,这个就比较容易了,直接删就可以啦。

    对于修改,我们直接打上标记覆盖就可以了。

    对于翻转,我们依然打上标记,不过等级比修改要低,如果既要修改又要翻转,那么就可以无视翻转。

    对于求和,使用sum数组直接求得即可。

    对于求最大子列,我们记录当前最大的,某个点包含最左端点的最大子列,包含最右端点的最大子列,然后比较即可。

    什么?没看明白,其实挺清楚的了,如果清楚splay的区间操作应该不是很难懂吧。。。

    那么说一下为什么不能一个个插入,可以发现的是,插入的数字不超过4000000个,那么如果我们要装下这么多数的话,就要开这么大的数组,一个貌似还能坚持,然后如果是8个。。。这个题就给了64MB内存,明显撑不下。所以建立一个队列收集已经删除的点,然后循环利用即可。

    Code

    #include<queue>
    #include<cmath>
    #include<cstdio>
    #include<cstring>
    #include<cstdlib>
    #include<iostream>
    #include<algorithm>
    #define inf 1000000000
    #define N 1000005
    using namespace std;
    int read()
    {
        int x=0,f=1;char ch=getchar();
        while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
        while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
        return x*f;
    }
    int n,m,rt,cnt;
    int a[N],id[N],fa[N],c[N][2];
    int sum[N],size[N],v[N],mx[N],lx[N],rx[N];
    bool tag[N],rev[N];
    queue<int> q;
    void update(int x)
    {
        int l=c[x][0],r=c[x][1];
        sum[x]=sum[l]+sum[r]+v[x];
        size[x]=size[l]+size[r]+1;
        mx[x]=max(mx[l],mx[r]);
        mx[x]=max(mx[x],rx[l]+v[x]+lx[r]);
        lx[x]=max(lx[l],sum[l]+v[x]+lx[r]);
        rx[x]=max(rx[r],sum[r]+v[x]+rx[l]);
    }
    void pushdown(int x)
    {
        int l=c[x][0],r=c[x][1];
        if(tag[x])
        {
            rev[x]=tag[x]=0;
            if(l)tag[l]=1,v[l]=v[x],sum[l]=v[x]*size[l];
            if(r)tag[r]=1,v[r]=v[x],sum[r]=v[x]*size[r];
            if(v[x]>=0)
            {
                if(l)lx[l]=rx[l]=mx[l]=sum[l];
                if(r)lx[r]=rx[r]=mx[r]=sum[r];
            }
            else 
            {
                if(l)lx[l]=rx[l]=0,mx[l]=v[x];
                if(r)lx[r]=rx[r]=0,mx[r]=v[x];
            }
        }
        if(rev[x])
        {
            rev[x]^=1;rev[l]^=1;rev[r]^=1;
            swap(lx[l],rx[l]);swap(lx[r],rx[r]);
            swap(c[l][0],c[l][1]);swap(c[r][0],c[r][1]);
        }
    }
    void rotate(int x,int &k)
    {
        int y=fa[x],z=fa[y],l,r;
        l=(c[y][1]==x);r=l^1;
        if(y==k)k=x;
        else c[z][c[z][1]==y]=x;
        fa[c[x][r]]=y;fa[y]=x;fa[x]=z;
        c[y][l]=c[x][r];c[x][r]=y;
        update(y);update(x);
    }
    void splay(int x,int &k)
    {
        while(x!=k)
        {
            int y=fa[x],z=fa[y];
            if(y!=k)
            {
                if(c[y][0]==x^c[z][0]==y)rotate(x,k);
                else rotate(y,k);
            }
            rotate(x,k);
        }
    }
    int find(int x,int rk)
    {
        pushdown(x);
        int l=c[x][0],r=c[x][1];
        if(size[l]+1==rk)return x;
        if(size[l]>=rk)return find(l,rk);
        return find(r,rk-size[l]-1);
    }
    void rec(int x)
    {
        if(!x)return;
        int l=c[x][0],r=c[x][1];
        rec(l);rec(r);q.push(x);
        fa[x]=c[x][0]=c[x][1]=0;
        tag[x]=rev[x]=0;
    }
    int split(int k,int tot)
    {
        int x=find(rt,k),y=find(rt,k+tot+1);
        splay(x,rt);splay(y,c[x][1]);
        return c[y][0];
    }
    void query(int k,int tot)
    {
        int x=split(k,tot);
        printf("%d
    ",sum[x]);
    }
    void modify(int k,int tot,int val)
    {
        int x=split(k,tot),y=fa[x];
        v[x]=val;tag[x]=1;sum[x]=size[x]*val;
        if(val>=0)lx[x]=rx[x]=mx[x]=sum[x];
        else lx[x]=rx[x]=0,mx[x]=val;
        update(y);update(fa[y]);
    }
    void rever(int k,int tot)
    {
        int x=split(k,tot),y=fa[x];
        if(!tag[x])
        {
            rev[x]^=1;
            swap(c[x][0],c[x][1]);
            swap(lx[x],rx[x]);
            update(y);update(fa[y]);
        }
    }
    void erase(int k,int tot)
    {
        int x=split(k,tot),y=fa[x];
        rec(x);c[y][0]=0;
        update(y);update(fa[y]);
    }
    void build(int l,int r,int f)
    {
        if(l>r)return;
        int mid=(l+r)>>1,now=id[mid],last=id[f];
        if(l==r)
        {
            sum[now]=a[l];size[now]=1;
            tag[now]=rev[now]=0;
            if(a[l]>=0)lx[now]=rx[now]=mx[now]=a[l];
            else lx[now]=rx[now]=0,mx[now]=a[l];
        }
        else build(l,mid-1,mid),build(mid+1,r,mid);
        v[now]=a[mid];fa[now]=last;update(now);
        c[last][mid>=f]=now;
       }
    void insert(int k,int tot)
    {
        for(int i=1;i<=tot;i++)a[i]=read();
        for(int i=1;i<=tot;i++)
            if(!q.empty())id[i]=q.front(),q.pop();
            else id[i]=++cnt;
        build(1,tot,0);int z=id[(1+tot)>>1];
        int x=find(rt,k+1),y=find(rt,k+2);
        splay(x,rt);splay(y,c[x][1]);
        fa[z]=y;c[y][0]=z;
        update(y);update(x);
    }
    int main()
    {
        //freopen("date.in","r",stdin);
        n=read();m=read();
        mx[0]=a[1]=a[n+2]=-inf;
        for(int i=1;i<=n;i++)a[i+1]=read();
        for(int i=1;i<=n+2;i++)id[i]=i;
        build(1,n+2,0);
        rt=(n+3)>>1;cnt=n+2;
        int k,tot,val;
        char ch[10];
        while(m--)
        {
            scanf("%s",ch);
            if(ch[0]!='M'||ch[2]!='X')k=read(),tot=read();
            if(ch[0]=='I')insert(k,tot);
            if(ch[0]=='D')erase(k,tot);
            if(ch[0]=='M')
            {
                if(ch[2]=='X')printf("%d
    ",mx[rt]);
                else val=read(),modify(k,tot,val);
            }
            if(ch[0]=='R')rever(k,tot);
            if(ch[0]=='G')query(k,tot);
        }
        return 0;
    }
    
  • 相关阅读:
    021.day21 反射 Class类 反射常用操作
    020.day20 线程概述 多线程优缺点 线程的创建 线程常用方法 生命周期 多线程同步
    019.day19 缓冲流 对象流 标准输入输出流
    018.day18 map集合如何实现排序 File类 IO流 字节流 字符流 编码
    017.day17 Map接口 克隆 treeSet集合排重缺陷
    016.day16 HashSet TreeSet 比较器Comparable Comparator
    015.day15
    014.day14
    013.day13
    线程
  • 原文地址:https://www.cnblogs.com/victorique/p/8969294.html
Copyright © 2011-2022 走看看