线段树 区间区间取最小值 HDU5306 Gorgeous Sequence

HDU5306 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

问题描述

有一个长度为n的序列a。 我们用ai表示此序列中的第i个元素。 您应该对此序列执行以下三种类型的操作。

0 x y t:对于每个x≤i≤y,我们使用min(ai,t)替换原始ai的值。
1 x y:打印x≤i≤y的ai最大值。
2 x y:打印x≤i≤y的ai的总和。

输入

输入的第一行是单个整数T,表示测试用例的数量。

第一行包含两个整数n和m,分别表示序列的长度和操作数。

第二行包含n个独立的整数a1,…,an(∀1≤i≤n,0≤ai<231)。

接下来的m行分别代表一个运算(1≤x≤y≤n,0≤t<231)。

保证T = 100,∑n≤1000000,∑m≤1000000。

输出

对于类型1或2的每个操作,请打印一行包含相应查询答案的行。

样本输入

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

样本输出

5
15
3
12

分析

每个节点维护最大值max,次大值se,区间和sum,最大值个数cnt
区间取最小值操作ai=min(ai,t)
1.如果max<=t,那么不需要进行修改
2.如果se<t<max,那么需要更新区间中那些最大值,区间和sum+=cnt*(t-max)
3.如果t<=se,那么就向下递归操作,然后向上更新
注意:区间和会超int ,所以用long long
不过要是所有变量都用long long 定义,可能会超时

#include<bits/stdc++.h>
#define ll long long
#define a u<<1
#define b u<<1|1
using namespace std;
const int N=1e6+7,M=N*4;
inline int read()
{
    register int s=0,w=1;
    register char ch=getchar();
    while(ch<'0'||ch>'9')
    {
        if(ch=='-')
        w=-1;
        ch=getchar();
    }
    while(ch>='0'&&ch<='9')
    {
        s=s*10+ch-'0';
        ch=getchar();
    }
    return w*s;
}
int t,n,m;
int w[N];
int mx[M],se[M],cn[M],tag[M],le[M],ri[M];
ll sum[M];
void pushup(int u)
{
    sum[u]=sum[a]+sum[b];
    if(mx[a]==mx[b])
    {
        mx[u]=mx[a];
        cn[u]=cn[a]+cn[b];
        se[u]=max(se[a],se[b]);
    }
    else if(mx[a]>mx[b])
    {
        mx[u]=mx[a];
        cn[u]=cn[a];
        se[u]=max(se[a],mx[b]);
    }
    else
    {
        mx[u]=mx[b];
        cn[u]=cn[b];
        se[u]=max(mx[a],se[b]);
    }
}
void pushdown(int u)
{
    if(tag[u]!=-1)
    {
        if(mx[a]>tag[u])
        {    
            sum[a]+=(ll)(tag[u]-mx[a])*cn[a];
            mx[a]=tag[a]=tag[u];
        }
        if(mx[b]>tag[u])
        {    
            sum[b]+=(ll)(tag[u]-mx[b])*cn[b];
            mx[b]=tag[b]=tag[u];
        }
        tag[u]=-1;
    }
}
void build(int u,int l,int r)
{
    tag[u]=-1,le[u]=l,ri[u]=r;
    if(l==r)
    {
        sum[u]=mx[u]=w[l],se[u]=-1,cn[u]=1;
    }
    else
    {
        int mid=l+r>>1;
        build(a,l,mid);
        build(b,mid+1,r);
        pushup(u);
    }
}
void modify_min(int u,int l,int r,int v)
{
    if(mx[u]<=v) return ;
    if(le[u]>=l&&ri[u]<=r&&se[u]<v)
    {
        sum[u]+=(ll)(v-mx[u])*cn[u];
        tag[u]=mx[u]=v;
        return ;
    }
    pushdown(u);
    int mid=le[u]+ri[u]>>1;
    if(mid>=l) modify_min(a,l,r,v);
    if(mid<r) modify_min(b,l,r,v);
    pushup(u);
}
int query_max(int u,int l,int r)
{
    if(le[u]>=l&&ri[u]<=r) return mx[u];
    pushdown(u);
    int mid=le[u]+ri[u]>>1;
    int ma=-1;
    if(mid>=l) ma=max(ma,query_max(a,l,r));
    if(mid<r) ma=max(ma,query_max(b,l,r));
    return ma;
}
ll query_sum(int u,int l,int r)
{
    if(le[u]>=l&&ri[u]<=r) return sum[u];
    pushdown(u);
    int mid=le[u]+ri[u]>>1;
    ll su=0;
    if(mid>=l) su+=query_sum(a,l,r);
    if(mid<r) su+=query_sum(b,l,r);
    return su;
} 
int main()
{
    t=read();
    while(t--)
    {
        n=read(),m=read();
        for(int i=1;i<=n;i++)
        w[i]=read();
        build(1,1,n);
        while(m--)
        {
            int op,x,y,z;
            op=read(),x=read(),y=read();
            if(op==0)
            {
                z=read();
                modify_min(1,x,y,z);
            }
            else if(op==1)
            printf("%d\n",query_max(1,x,y));
            else printf("%lld\n",query_sum(1,x,y));
        }
    }
    return 0;
} 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值