zoukankan      html  css  js  c++  java
  • bzoj5050: 建造摩天楼

    Description

    属于小Q管辖的n座摩天楼从左往右排成一排,编号依次为1到n,第i座摩天楼的高度为h_i。小Q会进行m次以下两种
    操作之一:
    2 l r,询问h_l+h_{l+1}+...+h_r。
    1 l r,对于第l到r的每座摩天楼i,如果上次操作结束时h_i<h_{i-1},则将第i座摩天楼再往上造一层,即h_i增加1。
    你可以认为h_0=正无穷。
    请写一个程序回答小Q的每个询问。

    Input

    第一行包含两个正整数n,m(1<=n<=100000,1<=m<=min(100000,2n)),分别表示摩天楼的数量以及操作的数量。
    第二行包含n个正整数h_1,h_2,...,h_n(1<=h_i<=n),表示每座楼的高度。
    接下来m行,每行三个正整数op,l,r(1<=op<=2,1<=l<=r<=n),分别表示每个操作。
    因为小Q觉得错乱不齐的建筑更加美观,因此你可以认为数据是完全随机的。

    Output

    对于每个询问输出一行一个整数,即区间内所有摩天楼的高度之和。

    可以发现对随机数据$h_i-h_{i-1}<0$的变化次数是O(n)的,因此可以用线段树维护操作,注意特判区间端点。维护区间内h的和,再记一些信息表示再操作几次$h_i-h_{i-1}<0$会出现变化,当出现变化时暴力修改。时间复杂度O(nlogn)。

    #include<bits/stdc++.h>
    typedef long long i64;
    const int N=1e5+7,inf=1e8;
    char ib[N*50],*ip=ib;
    int _(){
        int x=0;
        while(*ip<48)++ip;
        while(*ip>47)x=x*10+*ip++-48;
        return x;
    }
    int n,m,h[N],d[N],_l,_r;
    i64 _s;
    inline int min(int a,int b){return a<b?a:b;}
    inline int max(int a,int b){return a>b?a:b;}
    struct node;
    node*at(int x);
    struct node{
        node*lc,*rc;
        int L,R,M,a,sz,v1,v2,v3,cd,dd;
        i64 s;
        void add(int x){
            a+=x;
            s+=sz*i64(x);
            v1+=x,v2-=x;
            if(!M)v3+=dd*x;
        }
        void dn(){
            if(a)lc->add(a),rc->add(a),a=0;
        }
        void set(int x,int y){
            sz=d[L];
            v1=(x<0&&y==1)?x:-inf;
            v2=(x>=0&&y==-1)?x:inf;
            v3=x;
            dd=y;
        }
        void init(){
            s=h[L];
            set(h[L]-h[L-1],d[L]-d[L-1]);
        }
        void up(){
            s=lc->s+rc->s;
            sz=lc->sz+rc->sz;
            v1=max(lc->v1,rc->v1);
            v2=min(lc->v2,rc->v2);
            cd=lc->cd||rc->cd;
        }
        void addl(){
            if(M)dn(),(_l<=M?lc:rc)->addl(),up();
            else{
                cd=(!++v3);
                ++s,++v1,++v2;
            }
        }
        void addr(){
            if(M)dn(),(_r<=M?lc:rc)->addr(),up();
            else{
                cd=(!v3--);
                --v1,--v2;
            }
        }
        void add(){
            if(_l<=L&&R<=_r)return add(1);
            dn();
            if(_l<=M)lc->add();
            if(_r>M)rc->add();
            up();
        }
        void sum(){
            if(_l<=L&&R<=_r)return void(_s+=s);
            dn();
            if(_l<=M)lc->sum();
            if(_r>M)rc->sum();
        }
        bool ir(){
            return v1>=0||v2<0||cd;
        }
        void chk2(){
            if(M)dn(),(_l<=M?lc:rc)->chk2(),up();
            else{
                if(ir()){
                    _l=L+1;
                    d[L]^=1;
                    cd=0;
                }else _l=n+1;
                set(v3,d[L]-d[L-1]);
            }
        }
        void chk(){
            if(M)dn(),(lc->ir()?lc:rc)->chk(),up();
            else{
                _l=L+1;
                d[L]^=1;
                cd=0;
                set(v3,d[L]-d[L-1]);
            }
        }
    }ns[N*2],*np=ns,*rt;
    node*at(int x){
        node*w=rt;
        while(w->M){
            w->dn();
            w=x<=w->M?w->lc:w->rc;
        }
        return w;
    }
    node*build(int L,int R){
        node*w=np++;
        w->L=L,w->R=R;
        if(L<R){
            int M=w->M=(L+R)>>1;
            w->lc=build(L,M);
            w->rc=build(M+1,R);
            w->up();
        }else w->init();
        return w;
    }
    int main(){
        fread(ib,1,sizeof(ib),stdin);
        n=_(),m=_();
        h[0]=inf;
        for(int i=1;i<=n;++i)h[i]=_(),d[i]=h[i]<h[i-1];
        rt=build(1,n);
        for(int o;m;--m){
            o=_(),_l=_(),_r=_();
            if(o==1){
                if(d[_l])rt->addl();
                if(_r<n&&d[_r])++_r,rt->addr(),--_r;
                if(++_l<=_r)rt->add();
                while(rt->ir())for(rt->chk();_l<=n;rt->chk2());
                
            }else{
                _s=0;
                rt->sum();
                printf("%lld
    ",_s);
            }
        }
        return 0;
    }
  • 相关阅读:
    Security and Cryptography in Python
    Security and Cryptography in Python
    Security and Cryptography in Python
    Security and Cryptography in Python
    Security and Cryptography in Python
    Security and Cryptography in Python
    Security and Cryptography in Python
    微信小程序TodoList
    C语言88案例-找出数列中的最大值和最小值
    C语言88案例-使用指针的指针输出字符串
  • 原文地址:https://www.cnblogs.com/ccz181078/p/7690381.html
Copyright © 2011-2022 走看看