多校2 hdu 6315 Naive Operations (线段树)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6315

题意:给出初始数组a,元素值均为0,数据数组b,两种询问方式 add,x,y 表示在区间 [x,y] 中每个元素均+1,query x y,表示计算 {\color{Blue} \sum_{i=x}^{y}=ai/bi}

参考博客:

题解:线段树应用,我们首先我们在建立线段树之前应该思考的是线段树的节点维护一个什么值,

  1. 维护了b[i]的值,因为a[i]最初是0,所以在update过程中当a[i]>=b[i]时,a[i]/b[i]才>=1;

  2. 才会对sum有贡献,所以不妨维护b[i]的值,对每次区间更新,将区间中的b[i]减1,当b[i]减到0时,更新sum的值+1,然后b[i]更新回初始的b[i]的值

  3. 整个更新过程中需要维护lazy标志、sum当前子树中0的个数(即sum+1的次数)、minx当前子树中最小的b[i]值

  4. lazy是a数组向下推的标志,就是加的次数,其实就是b要减的数

 

代码:

#include<cstdio>
#include<algorithm>
#include<cstdio>

using namespace std;

const int maxn=100010;
int n,m,x,y;
int num[maxn];
char op[10];

struct node{
    int minx,sum,add;
}T[maxn<<2];

void build(int rt,int l,int r)
{
    T[rt].add=0;
    if(l==r){
        T[rt].minx=num[l];
        T[rt].sum=0;
        return;
    }

    int mid=(l+r)>>1;

    build(rt<<1,l,mid);
    build(rt<<1|1,mid+1,r);

    T[rt].minx=min(T[rt<<1].minx,T[rt<<1|1].minx);
    T[rt].sum=T[rt<<1].sum+T[rt<<1|1].sum;

}

void pushdown(int rt,int l,int r)
{
    if(!T[rt].add) return;
    int mid=(l+r)>>1;

    T[rt<<1].minx+=T[rt].add;
    T[rt<<1|1].minx+=T[rt].add;

    T[rt<<1].add+=T[rt].add;
    T[rt<<1|1].add+=T[rt].add;

    T[rt].add=0;
}
/*
L R 表示查询区间
l r 表示当前区间
*/

///这里多了一个ok,不像我们之前的,不用ok,直接算,因为之前成段更新时
///可以很快从当前节点给算出来,但这里不能,只能通过叶子节点给算出来
void update(int rt,int l,int r,int L,int R,bool ok) 
{
    if(L>r||R<l) return;

    if(L<=l&&r<=R){
            if(ok){
        T[rt].minx--;
        T[rt].add--;
            }
        if(T[rt].minx>0) return;
        if(l==r){
            if(T[rt].minx==0){
                T[rt].sum++;
                T[rt].minx=num[l];
                return;
            }
        }

        ok=false;
    }

    pushdown(rt,l,r);

    int mid=(l+r)>>1;
    update(rt<<1,l,mid,L,R,ok);
    update(rt<<1|1,mid+1,r,L,R,ok);

    T[rt].minx=min(T[rt<<1].minx,T[rt<<1|1].minx);
    T[rt].sum=T[rt<<1].sum+T[rt<<1|1].sum;
}

int query(int rt,int l,int r,int L,int R)
{
    if(L>r||R<l) return 0;
    if(L<=l&&r<=R) return T[rt].sum;

    int mid=(l+r)>>1;

    return query(rt<<1,l,mid,L,R)+query(rt<<1|1,mid+1,r,L,R);
}
int main()
{

    while(~scanf("%d%d",&n,&m))
    {
        for(int i=1;i<=n;i++)
            scanf("%d",&num[i]);
        build(1,1,n);

        while(m--)
        {
            scanf("%s%d%d",op,&x,&y);
            if(op[0]=='a') update(1,1,n,x,y,1);
            else printf("%d\n",query(1,1,n,x,y));
        }
    }
    return 0;
}

 

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值