zoukankan      html  css  js  c++  java
  • 【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
    ",sgt.querymax(1,1,n,l,r));
                if(opt==2)printf("%lld
    ",sgt.querysum(1,1,n,l,r));
            }
        }
    }
  • 相关阅读:
    UML 入门课程
    在Visio中建立数据库模型的步骤
    phpMyAdmin
    采用软件负载均衡器实现web服务器集群
    Javascript 调用后台方法
    log4net 使用相关要点汇总
    静栈/动堆
    国外web 2.0网站模板
    yum应用学习笔记
    分页 : 存储分页 :row_number
  • 原文地址:https://www.cnblogs.com/zcysky/p/7384259.html
Copyright © 2011-2022 走看看