【hdu5603】:Gorgeous Sequence

Gorgeous Sequence

Problem Description

There is a sequence a of length n. We use ai to denote the i-th element in this sequence. You should do the following three types of operations to this sequence.

0 x y t: For every x≤i≤y, we use min(ai,t) to replace the original ai's value.
1 x y: Print the maximum value of ai that x≤i≤y.
2 x y: Print the sum of ai that x≤i≤y.

Input

The first line of the input is a single integer T, indicating the number of testcases.

The first line contains two integers n and m denoting the length of the sequence and the number of operations.
The second line contains n separated integers a1,…,an (∀1≤i≤n,0≤ai<231).
Each of the following m lines represents one operation (1≤x≤y≤n,0≤t<231).

It is guaranteed that T=100, ∑n≤1000000, ∑m≤1000000.

Output

For every operation of type 1 or 2, print one line containing the answer to the corresponding query.

Sample Input

1
5 5
1 2 3 4 5
1 1 5
2 1 5
0 3 5 3
1 1 5
2 1 5

Sample Output

5
15
3
12

Hint

Please use efficient IO method

Author

XJZX

Solution

题目大意就是维护一个区间支持
1.区间 [l,r] 对 x 取 min
2.区间查询最大值
3.区间查询和

emmm 没看题解前 我只会打暴力
事实上
这tm就是一个xjb搞的线段树裸体23333

然后聪明的你一下子就想到了
1.维护一个区间最大值
2.维护一个区间次大值

然后对于一次修改 x,如果 区间最大值还小于x 那么就可以直接return
如果x 小于最大值 但是同时也大于等于次大值
我们可以直接将 sum = cnt*(max-x) (cnt是这个区间中最大值出现的个数)

然后如果都不满足的话,我们只能老老实实的分治修改子区间
对于如何修改子区间,大佬们都可以直接dfs。
emmmm
其实貌似可以直接update,就将两个子区间的最大值改成 本区间的最大值(和题目中的操作等价)

最后说一下pushup,pushdown
pushup在普通线段树的基础上 要多维护一个次大值
和vijos的小白逛公园类似,可以在两个子区间里找一个较小的最大值就可以

pushdown的意义在于 我们对一个区间进行了修改操作后,他的最大值要么不变或变小
此时我们还没有直接对他的子区间进行正确的修改。
对于子区间中大于当前修改后的最大值 一定是不合法的
我们需要将两个区间的最大值更新为父亲区间的最大值(和题目中的操作等价)

两个操作都和题目中的操作等价,所以这问题个人认为会变简单很多。
复杂度我太菜了不会证明....大家可以移步一位大佬的博客
传送门

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
inline int read(){
    int rtn=0,f=1;char ch=getchar();
    while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
    while(isdigit(ch))rtn=(rtn<<1)+(rtn<<3)+ch-'0',ch=getchar();
    return rtn*f;
}
#define maxn (int)(1e6+10)
#define inf 1e9
namespace SegmentTree{
    inline void update(int,int,int,int,int,int);
    inline void pushdown(int,int,int);
    struct node{
        int max,cnt,sed;LL sum;
    }T[maxn<<3];
    inline void pushup(int p){
        T[p].sum=T[p<<1].sum+T[p<<1|1].sum;
        T[p].max=max(T[p<<1].max,T[p<<1|1].max);
        T[p].sed=-inf,T[p].cnt=0;
        if(T[p].max==T[p<<1].max)T[p].cnt+=T[p<<1].cnt;
        else if(T[p].max>T[p<<1].max)T[p].sed=T[p<<1].max;
        if(T[p].max==T[p<<1|1].max)T[p].cnt+=T[p<<1|1].cnt;
        else if(T[p].max>T[p<<1|1].max)T[p].sed=T[p<<1|1].max;
        T[p].sed=max(T[p].sed,max(T[p<<1].sed,T[p<<1|1].sed));
    }
    inline void build(int p,int l,int r){
        if(l==r){
            T[p].sum=T[p].max=read();T[p].cnt=1;T[p].sed=-inf;return;
        }
        int mid=l+r>>1;
        build(p<<1,l,mid);
        build(p<<1|1,mid+1,r);
        pushup(p);
    }
    inline void update(int p,int lp,int rp,int l,int r,int v){
        int mid=lp+rp>>1;
        if(lp==l&&rp==r){
            if(v>=T[p].max)return;
            else if(v<T[p].max&&v>=T[p].sed){
                T[p].sum-=(LL)T[p].cnt*(T[p].max-v);
                T[p].max=v;return;
            }
            update(p<<1,lp,mid,l,mid,v);
            update(p<<1|1,mid+1,rp,mid+1,r,v);
            pushup(p);return;
        }
        pushdown(p,lp,rp);
        if(r<=mid)update(p<<1,lp,mid,l,r,v);
        else if(l>mid)update(p<<1|1,mid+1,rp,l,r,v);
        else update(p<<1,lp,mid,l,mid,v),update(p<<1|1,mid+1,rp,mid+1,r,v);
        pushup(p);
    }
    inline void pushdown(int p,int l,int r){
        int mid=l+r>>1;
        if(T[p].max<T[p<<1].max)update(p<<1,l,mid,l,mid,T[p].max);
        if(T[p].max<T[p<<1|1].max)update(p<<1|1,mid+1,r,mid+1,r,T[p].max);
    }
    inline LL query_sum(int p,int lp,int rp,int l,int r){
        if(lp==l&&rp==r)return T[p].sum;
        pushdown(p,lp,rp);
        int mid=lp+rp>>1;
        if(r<=mid)return query_sum(p<<1,lp,mid,l,r);
        else if(l>mid)return query_sum(p<<1|1,mid+1,rp,l,r);
        else return query_sum(p<<1,lp,mid,l,mid)+query_sum(p<<1|1,mid+1,rp,mid+1,r);
    }
    inline int query_max(int p,int lp,int rp,int l,int r){
        if(lp==l&&rp==r)return T[p].max;
        pushdown(p,lp,rp);
        int mid=lp+rp>>1;
        if(r<=mid)return query_max(p<<1,lp,mid,l,r);
        else if(l>mid)return query_max(p<<1|1,mid+1,rp,l,r);
        else return max(query_max(p<<1,lp,mid,l,mid),query_max(p<<1|1,mid+1,rp,mid+1,r));
    }
}using namespace SegmentTree;
int n,m;
int main(){
    int t=read();
    while(t--){
        n=read(),m=read();
        build(1,1,n);
        for(int i=1;i<=m;i++){
            int opt=read(),l=read(),r=read();
            if(opt==0)update(1,1,n,l,r,read());
            else if(opt==1)printf("%d\n",query_max(1,1,n,l,r));
            else if(opt==2)printf("%lld\n",query_sum(1,1,n,l,r));
        }
    }
    return 0;
}

转载于:https://www.cnblogs.com/DexterYsw/p/7910870.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值