【HDU5306】Gorgeous Sequence

这个题目是Segment-Tree-beats的论文的第一题。

首先我们考虑下这个问题的不同之处在于,有一个区间对x取max的操作。

那么如何维护这个操作呢?

就是对于线段树的区间,维护一个最大值标记,最大值出现次数,以及严格次大值。

接下来考虑处理操作。

首先如果x>maxv[o]证明已经是无所谓的,所以应该直接放弃。

如果v处于semx[o]<x<maxv[o],证明只有最大值需要被修改。

其他的情况就继续向下递进就可以了。

那么我们证明一下为什么这么做复杂度是对的。

首先,如同论文中所说的,对于每个maxv可以看作是一个标记,把相同的maxv合并到第一个点,

可以发现semx的含义就是子树中最大的maxv。(因为最大值已经被缩到了这个点上)

每次暴力进入这些节点的时候,实际上就是将标记进行合并。

(也就是文章中所说的标记回收的理论)

这个题的难点就是为什么我这么暴力的回收依然可以是一个log的。

在每一次操作后会产生一类新的标记。

那么每次标记回收实际上就是有一类标记的权值-=1

#include<bits/stdc++.h>
typedef long long ll;
using namespace std;
const int N=1e6+5;
int a[N],n,m;
struct Segment_Tree{
#define lson (o<<1)
#define rson (o<<1|1)
    int maxv[N<<2],cntv[N<<2],semx[N<<2];
    ll sumv[N<<2];
    inline void pushup(int o){
        sumv[o]=sumv[lson]+sumv[rson];
        maxv[o]=max(maxv[lson],maxv[rson]);
        semx[o]=max(semx[lson],semx[rson]);cntv[o]=0;
        if(maxv[lson]!=maxv[rson])semx[o]=max(semx[o],min(maxv[lson],maxv[rson]));
        if(maxv[o]==maxv[lson])cntv[o]+=cntv[lson];
        if(maxv[o]==maxv[rson])cntv[o]+=cntv[rson];
    }
    inline void puttag(int o,int v){
        if(v>=maxv[o])return;
        sumv[o]+=1LL*(v-maxv[o])*cntv[o];maxv[o]=v;
    }
    inline void pushdown(int o){puttag(lson,maxv[o]);puttag(rson,maxv[o]);}
    inline void build(int o,int l,int r){
        if(l==r){
            sumv[o]=maxv[o]=a[l];cntv[o]=1;semx[o]=-1;
            return;
        }
        int mid=(l+r)>>1;
        build(lson,l,mid);build(rson,mid+1,r);
        pushup(o);
    }
    inline void optmax(int o,int l,int r,int ql,int qr,int v){
        if(v>=maxv[o])return;
        if(ql<=l&&r<=qr&&v>semx[o]){puttag(o,v);return;}
        int mid=(l+r)>>1;pushdown(o);
        if(ql<=mid)optmax(lson,l,mid,ql,qr,v);
        if(qr>mid)optmax(rson,mid+1,r,ql,qr,v);
        pushup(o);
    }
    inline ll querysum(int o,int l,int r,int ql,int qr){
        if(ql<=l&&r<=qr)return sumv[o];
        int mid=(l+r)>>1;pushdown(o);ll ans=0;
        if(ql<=mid)ans+=querysum(lson,l,mid,ql,qr);
        if(qr>mid)ans+=querysum(rson,mid+1,r,ql,qr);
        return ans;
    }
    inline int querymax(int o,int l,int r,int ql,int qr){
        if(ql<=l&&r<=qr)return maxv[o];
        pushdown(o);int mid=(l+r)>>1,ans=-1;
        if(ql<=mid)ans=max(ans,querymax(lson,l,mid,ql,qr));
        if(qr>mid)ans=max(ans,querymax(rson,mid+1,r,ql,qr));
        return ans;
    }
}sgt;
inline int read(){
    int f=1,x=0;char ch;
    do{ch=getchar();if(ch=='-')f=-1;}while(ch<'0'||ch>'9');
    do{x=x*10+ch-'0';ch=getchar();}while(ch>='0'&&ch<='9');
    return f*x;
}
int main(){
    int T=read();
    while(T--){
        n=read();m=read();
        for(int i=1;i<=n;i++)a[i]=read();
        sgt.build(1,1,n);
        while(m--){
            int opt=read(),l=read(),r=read();
            if(opt==0){
                int v=read();
                sgt.optmax(1,1,n,l,r,v);
            }
            if(opt==1)printf("%d\n",sgt.querymax(1,1,n,l,r));
            if(opt==2)printf("%lld\n",sgt.querysum(1,1,n,l,r));
        }
    }
}

 

posted @ 2017-08-17 20:36  zcysky  阅读(533)  评论(0编辑  收藏  举报