ccz181078

  博客园 :: 首页 :: 博问 :: 闪存 :: 新随笔 :: 联系 :: :: 管理 ::

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\n",_s);
        }
    }
    return 0;
}

 

posted on 2017-10-19 06:45  nul  阅读(216)  评论(0编辑  收藏  举报