zoukankan      html  css  js  c++  java
  • bzoj1500

    1500: [NOI2005]维修数列

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

    打掉大boss了,一边抄一边写。

    因为插入的数总共为4000000个,所以我们可以暴力地每个点直接插入,插入时,我们把新插入的元素建成一棵小树,再挂到大树上。

    删除一样,转到那个节点,然后删除,但是这里要一个个删除,因为内存要循环利用。直接暴力删除,把节点放进一个栈中,用的时候拿出来,因为一共只有4000000个元素,绝对不会超时。

    修改是打一个懒标记,tag[x]=c,然后pushdown即可。

    翻转同上。

    求和也是利用标记,sum[x]=sum[child[x][0]]+sum[child[x][1]]+key[x]

    最后一个我们需要维护三个值,x节点表示的区间,lm[x]表示从x节点的区间最左端开始,最大的和是多少,rm[x]则是右边,mx[x]则表示这个节点的最大和

    mx[x]=max(mx[child[x][0]],mx[child[x][1]],max(rm[child[x][0]],0)+key[x]+max(0,lm[child[x][1]])) 自己拿手画一下,想一下即可。

    注意:pushdown要更新自己的sum[x],key[x],然后也要把自己的儿子节点child[x][0],child[x][1]也更新掉,翻转也是,我不知道为什么,这里查了两个小时才发现。

    makesame的初始值要设成-1001,因为更新的数在[-1000,1000]之间。

    #include<cstdio>
    #include<cstring>
    #include<stack>
    #include<vector>
    using namespace std;
    #define N 1000010
    #define inf -1101
    stack<int> s;
    int n,m,root,cnt;
    int size[N],child[N][2],lm[N],rm[N],key[N],mx[N],sum[N];
    int tag1[N],tag2[N],fa[N],a[N];
    void update(int x)
    {
        size[x]=size[child[x][0]]+size[child[x][1]]+1;
        sum[x]=sum[child[x][0]]+sum[child[x][1]]+key[x];
        mx[x]=max(max(mx[child[x][0]],mx[child[x][1]]),
                        max(rm[child[x][0]],0)+key[x]+max(lm[child[x][1]],0));
        lm[x]=max(lm[child[x][0]],sum[child[x][0]]+key[x]+max(0,lm[child[x][1]]));
        rm[x]=max(rm[child[x][1]],sum[child[x][1]]+key[x]+max(0,rm[child[x][0]]));
    }
    void paint(int x)
    {
        tag2[x]^=1;
        swap(child[x][0],child[x][1]);
        swap(lm[x],rm[x]);
    }
    void paint(int x,int c)
    {
        if(!x) return;
        tag1[x]=key[x]=c; sum[x]=size[x]*c;
        lm[x]=rm[x]=mx[x]=max(sum[x],key[x]);
    }
    void pushdown(int x)
    {
        if(tag1[x]!=inf)
        {
            paint(child[x][0],tag1[x]);//更新儿子节点 
            paint(child[x][1],tag1[x]);//更新儿子节点 
            tag1[x]=inf;
        }
        if(tag2[x])
        {
            tag2[x]^=1;
            if(child[x][0]) paint(child[x][0]);//更新儿子节点 
            if(child[x][1]) paint(child[x][1]);//更新儿子节点 
        }
    }
    void zig(int x)
    {
        int y=fa[x];
        fa[x]=fa[y]; child[fa[x]][child[fa[x]][1]==y]=x;
        child[y][0]=child[x][1]; 
        fa[child[x][1]]=y;
        child[x][1]=y; fa[y]=x;
        update(y); update(x);
    }
    void zag(int x)
    {
        int y=fa[x];
        fa[x]=fa[y]; child[fa[x]][child[fa[x]][1]==y]=x;
        child[y][1]=child[x][0]; 
        fa[child[x][0]]=y;
        child[x][0]=y; fa[y]=x;
        update(y); update(x);
    }
    void splay(int x,int t)
    {
        while(fa[x]!=t)
        {
            pushdown(x);
            int y=fa[x],z=fa[y];
            if(z==t)
            {
                x==child[y][0]?zig(x):zag(x); break;
            } 
            x==child[y][0]?zig(x):zag(x);
            x==child[z][0]?zig(x):zag(x);
        }
        if(!t) root=x;
        update(root);
    }
    int find(int x,int rank)
    {
        pushdown(x);
        if(size[child[x][0]]+1==rank) return x;
        if(size[child[x][0]]>=rank) return find(child[x][0],rank);
        else return find(child[x][1],rank-size[child[x][0]]-1);    
    }
    int newnode()
    {
        int ret=0;
        if(!s.empty()) 
        {
            ret=s.top();
            s.pop();
        } else ret=++cnt;
        return ret;
    }
    void build(int l,int r,int&x,int last)
    {
        int mid=(l+r)>>1;
        x=newnode(); key[x]=a[mid]; fa[x]=last; 
        if(l<=mid-1) build(l,mid-1,child[x][0],x);
        if(mid+1<=r) build(mid+1,r,child[x][1],x);
        update(x);
    }
    void insert(int l,int r)
    {
        int x=find(root,l),y=find(root,l+1);//在l之后在l+1之前 
        splay(x,0); splay(y,root);
        for(int i=1;i<=r-l+1;i++) scanf("%d",&a[i]);
        build(1,r-l+1,child[child[root][1]][0],child[root][1]);
        update(child[root][1]); update(root);
    }
    void erase(int&x)
    {
        if(!x) return;
        s.push(x);
        fa[x]=0; key[x]=size[x]=sum[x]=tag2[x]=0;
        tag1[x]=inf;
        lm[x]=rm[x]=mx[x]=-(1<<30);
        erase(child[x][0]);
        erase(child[x][1]);
        x=0;
    }
    void del(int l,int r)
    {
        int x=find(root,l-1),y=find(root,r+1);
        splay(x,0); splay(y,root);
        erase(child[child[root][1]][0]);
        update(child[root][1]); update(root);
    }
    void makesame(int l,int r,int c)
    {
        int x=find(root,l-1),y=find(root,r+1);
        splay(x,0); splay(y,root);
        paint(child[child[root][1]][0],c);//更新儿子节点 
        update(child[root][1]); update(root);
        splay(child[child[root][1]][0],0);
    }
    void reverse(int l,int r)
    {
        int x=find(root,l-1),y=find(root,r+1);
        splay(x,0); splay(y,root);
        int b=child[child[root][1]][0];
        if(b) paint(b);//更新儿子节点 
        splay(child[child[root][1]][0],0);
    }
    void getsum(int l,int r)
    {
        int x=find(root,l-1),y=find(root,r+1);
        splay(x,0); splay(y,root);
        printf("%d
    ",sum[child[child[root][1]][0]]);
    }
    void maxsum()
    {
        printf("%d
    ",mx[root]);
    }
    int main()
    {
        for(int i=1;i<=N;i++) tag1[i]=inf;
        scanf("%d%d",&n,&m);
        for(int i=2;i<=n+1;i++)
        {
            scanf("%d",&a[i]);
        }
        mx[1]=mx[n+2]=lm[1]=lm[n+2]=rm[1]=rm[n+2]=mx[0]=
        lm[0]=rm[0]=a[1]=a[n+2]=-(1<<30);
        int x; build(1,n+2,x,0);
        root=1;
        while(m--)
        {    
            char s[10]; int pos,tot,c; scanf("%s",s);    
            if(s[2]=='S')
            {
                scanf("%d%d",&pos,&tot);
                insert(pos+1,pos+tot);
            }
            if(s[2]=='L')
            {
                scanf("%d%d",&pos,&tot);
                del(pos+1,pos+tot);
            }
            if(s[2]=='K')
            {
                scanf("%d%d%d",&pos,&tot,&c);
                if(tot>0) makesame(pos+1,pos+tot,c);
            }
            if(s[2]=='V')
            {
                scanf("%d%d",&pos,&tot);
                reverse(pos+1,pos+tot);
            }
            if(s[2]=='T')
            {
                scanf("%d%d",&pos,&tot);
                getsum(pos+1,pos+tot);
            }
            if(s[2]=='X')
            {
                maxsum();
            }
        }
        return 0;
    }
    View Code
  • 相关阅读:
    页面上一些小icon的制作方法及技术选择
    移动端h5页面touch事件与点击穿透问题
    浅析 jquerydom操作方法--remove(),detach(),empty()
    jquery中attr和prop的区别
    正则表达式的基本入门
    浏览器对中文标点符号折行的处理差异
    关于阴影:box-shadow
    ubuntu nginx ftp 配置图片服务器
    ubuntu 18 安装ftp 并远程配置访问用户
    WIn10系统软件默认安装c盘后消失看不见问题
  • 原文地址:https://www.cnblogs.com/19992147orz/p/6246796.html
Copyright © 2011-2022 走看看