【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));
        }
    }
}
时间: 2024-10-12 15:38:33

【HDU5306】Gorgeous Sequence的相关文章

【hdu5306】Gorgeous Sequence 线段树区间最值操作

题目描述 给你一个序列,支持三种操作: $0\ x\ y\ t$ :将 $[x,y]$ 内大于 $t$ 的数变为 $t$ :$1\ x\ y$ :求 $[x,y]$ 内所有数的最大值:$2\ x\ y$ :求 $[x,y]$ 内所有数的和. 多组测试数据,$\sum n,\sum m\le 10^6$ 题解 线段树区间最值操作 对于线段树上的一个节点,维护对应区间的:最大值 $mx$ .最大值个数 $c$ 及严格次大值 $se$ .那么对于一次区间最小值操作: 如果 $t\ge mx$ ,则这个

【HDU5306】【DTOJ2481】Gorgeous Sequence【线段树】

待填坑 代码: #include<iostream> #include<cstdio> #include<cstdlib> #include<cstring> #include<string> #define ll long long using namespace std; int T,n,m; ll a[1000001]; class Segtree { public: ll sum[1000001*5],mx[1000001*5],smx[

【BZOJ1367】[Baltic2004]sequence 左偏树

[BZOJ1367][Baltic2004]sequence Description Input Output 一个整数R Sample Input 7 9 4 8 20 14 15 18 Sample Output 13 HINT 所求的Z序列为6,7,8,13,14,15,18.R=13 题解:详见论文 然而本题要求z[i]严格递增,那就让所有t[i]-=i就好了 #include <cstdio> #include <cstring> #include <iostrea

【leetcode】 Permutation Sequence

问题: 对于给定序列1...n,permutations共有 n!个,那么任意给定k,返回第k个permutation.0 < n < 10. 分析: 这个问题要是从最小开始直接到k,估计会超时,受10进制转换为二进制的启发,对于排列,比如 1,2,3 是第一个,那么3!= 6,所以第6个就是3,2,1.也就是说,从开始的最小的序列开始,到最大的序列,就是序列个数的阶乘数.那么在1,3 , 2的时候呢?调整一下,变成2,1,3,就可以继续. 实现: int getFactorial(int n

【POJ2778】DNA Sequence(AC自动机)

题意: 生物课上我们学到,DNA序列中只有A, C, T和G四种片段. 经科学发现,DNA序列中,包含某些片段会产生不好的基因,如片段"ATC"是不好片段,则"AGATCC", "CATCAA", "ATCATC"都是不好的DNA序列,这些不好片段我们可以称为病毒片段. 现在已知m个病毒片段, 问长度为n的DNA序列,有多少种可能不包含病毒片段.答案可能很大,取模 100000. [数据规模和约定] 0<=m<=1

【leetcode】 Permutation Sequence (middle)

The set [1,2,3,…,n] contains a total of n! unique permutations. By listing and labeling all of the permutations in order,We get the following sequence (ie, for n = 3): "123" "132" "213" "231" "312" "3

【转】oracle sequence

原文链接  http://www.cnblogs.com/hyzhou/archive/2012/04/12/2444158.html ORACLE SEQUENCE用法 在oracle中sequence就是序号,每次取的时候它会自动增加.sequence与表没有关系. 1.Create Sequence 首先要有CREATE SEQUENCE或者CREATE ANY SEQUENCE权限. 创建语句如下: 复制代码 CREATE SEQUENCE seqTest INCREMENT BY 1

【LeetCode】Permutation Sequence

Permutation Sequence The set [1,2,3,…,n] contains a total of n! unique permutations. By listing and labeling all of the permutations in order,We get the following sequence (ie, for n = 3): "123" "132" "213" "231" &q

【bzoj1367】[Baltic2004]sequence

2016-05-31 17:31:26 1 #include<bits/stdc++.h> 2 #define inf 1000000000 3 #define ll long long 4 #define N 1000005 5 using namespace std; 6 int read(){ 7 int x=0,f=1;char ch=getchar(); 8 while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} 9 wh