HDU 5306 Gorgeous Sequence(线段树)

http://acm.hdu.edu.cn/showproblem.php?pid=5306

题意:对于数组 a,三种操作

0 x y t,将区间[x,y]内所有大于t的数换成t

1 x y:输出区间[x,y]内最大值

2 x y:输出区间[x,y]内的所有数的和

思路:这个题很容易固定思维,理解错题意,理解成区间更新成所有数的最小值,,本人一开始也理解错了。。上一次做这个题,因为后期看题解发现读错题。就直接看了一下思路,交了题解,就直接往下进行了,这次就是自己又敲了一遍,因为听其他人说挺烦的,,感觉还可以,就是得想明白了,细节有点多,。

建线段树,每个区间记录区间最大,区间次大值,区间最大值数量,区间和。

每次更新的时候要继续实现这四个记录值的更新完全。满满的做,得注意力十分集中才行,因为细节真的多QAQ

查找什么的就很普通了,跟普通的区间更新一样,要记得维护左右下区间的值。

 

代码:

#include<bits/stdc++.h>
using namespace std;
long long p,n,m,x,y,t,a[1000005];
struct AA
{
    long long maxx,maxn,sum,num;
}pos[4000020];
void build(int rt,int l,int r)
{
    if(l==r) {pos[rt].maxx=a[l];pos[rt].maxn=-1;pos[rt].num=1;pos[rt].sum=a[l];return;}
    int mid=(l+r)/2;
    build(rt<<1,l,mid);
    build(rt<<1|1,mid+1,r);
    pos[rt].maxx=max(pos[rt<<1].maxx,pos[rt<<1|1].maxx);
    pos[rt].sum=pos[rt<<1].sum+pos[rt<<1|1].sum;
    if(pos[rt<<1].maxx==pos[rt<<1|1].maxx)
        {pos[rt].num=pos[rt<<1].num+pos[rt<<1|1].num;
        pos[rt].maxn=max(pos[rt<<1].maxn,pos[rt<<1|1].maxn);}
    else
    {pos[rt].maxn=max(max(pos[rt<<1].maxn,pos[rt<<1|1].maxn),min(pos[rt<<1].maxx,pos[rt<<1|1].maxx));
    pos[rt].num=pos[rt<<1].maxx>pos[rt<<1|1].maxx?pos[rt<<1].num:pos[rt<<1|1].num;}
    return;
}
void BB(int rt,long long ma)
{
    if(ma>=pos[rt].maxx) return;
    pos[rt].sum-=pos[rt].num*(pos[rt].maxx-ma);
    pos[rt].maxx=ma;
}
void pushdown(int rt)
{
    BB(rt<<1,pos[rt].maxx);
    BB(rt<<1|1,pos[rt].maxx);
}
void change(int rt,int l,int r,int L,int R,long long z)
{
    if(pos[rt].maxx<=z) return;
    if(L<=l&&r<=R&&pos[rt].maxn<z) {
            BB(rt,z);
            return;}
    int mid=(l+r)/2;
    pushdown(rt);
    if(R<=mid) change(rt<<1,l,mid,L,R,z);
    else if(L>mid) change(rt<<1|1,mid+1,r,L,R,z);
    else {
        change(rt<<1,l,mid,L,R,z);
        change(rt<<1|1,mid+1,r,L,R,z);
    }
    pos[rt].maxx=max(pos[rt<<1].maxx,pos[rt<<1|1].maxx);
    pos[rt].sum=pos[rt<<1].sum+pos[rt<<1|1].sum;
    if(pos[rt<<1].maxx==pos[rt<<1|1].maxx)
        {pos[rt].num=pos[rt<<1].num+pos[rt<<1|1].num;
        pos[rt].maxn=max(pos[rt<<1].maxn,pos[rt<<1|1].maxn);}
    else
    {pos[rt].maxn=max(max(pos[rt<<1].maxn,pos[rt<<1|1].maxn),min(pos[rt<<1].maxx,pos[rt<<1|1].maxx));
    pos[rt].num=pos[rt<<1].maxx>pos[rt<<1|1].maxx?pos[rt<<1].num:pos[rt<<1|1].num;}
    return;
}
long long query(int rt,int l,int r,int L,int R)
{
    if(L<=l&&r<=R)
    {
        return pos[rt].maxx;
    }
    pushdown(rt);
    int mid=(l+r)/2;
    if(R<=mid) return query(rt<<1,l,mid,L,R);
    else if(L>mid) return query(rt<<1|1,mid+1,r,L,R);
    else return max(query(rt<<1,l,mid,L,R),query(rt<<1|1,mid+1,r,L,R));
}
long long querysum(int rt,int l,int r,int L,int R)
{
    if(L<=l&&r<=R)
    {
        return pos[rt].sum;
    }
    pushdown(rt);
    int mid=(l+r)/2;
    if(R<=mid) return querysum(rt<<1,l,mid,L,R);
    else if(L>mid) return querysum(rt<<1|1,mid+1,r,L,R);
    else return querysum(rt<<1,l,mid,L,R)+querysum(rt<<1|1,mid+1,r,L,R);
}
int main()
{
    int T;
   scanf("%d",&T);
   while(T--)
   {
       scanf("%lld%lld",&n,&m);
       for(int i=1;i<=n;i++)
        scanf("%lld",&a[i]);
       build(1,1,n);
       while(m--)
       {
           scanf("%lld%lld%lld",&p,&x,&y);
           if(p==0)
           {
               scanf("%lld",&t);
               change(1,1,n,x,y,t);
           }
           else if(p==1)
           {
               printf("%lld\n",query(1,1,n,x,y));
           }
           else if(p==2)
           {
               printf("%lld\n",querysum(1,1,n,x,y));
           }
       }
   }

}

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值