HDU6315(线段树维护区间最小值和区间求和)

题意

给定一个初始数组b和一个初始值全部为0的数组a,每次操作可以在给定的区间(l,r)内让a[i](l=<i<=r)加一,或者查询区间区间(l,r)中a[i]/b[i](l=<i<=r)(向下取整取整)的和。

题解

a[i]/b[i]向下取整,那么a[i]每次加1,a[i]加b[i]次就对总和的贡献加1。那么我们维护一个b数组最小值,每次更新区间最小值tree[rt].mi。当更新时发现tree[rt].mi=0,更新至叶子节。

#include<cstdio>
#include<algorithm>
#include<string.h>

using namespace std;

typedef long long ll;
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
const int INF = 0x3f3f3f3f;
const long long mod = 1e9 + 7;
const int maxn = 1e5 + 10;

double add[maxn<<2], sum[maxn<<2];
struct Node {
    int l, r;
    ll b;
    ll value;
    int lazy;
    int mi;
    int mid() { return (l+r)>>1;}
}tree[maxn<<2];
void pushdown(int rt)
{
    if(tree[rt].lazy > 0) {
        tree[rt<<1].lazy += tree[rt].lazy;
        tree[rt<<1|1].lazy += tree[rt].lazy;
        tree[rt<<1].mi -= tree[rt].lazy;
        tree[rt<<1|1].mi -= tree[rt].lazy;
        tree[rt].lazy = 0;
    }
}
void pushup(int rt)
{
    tree[rt].mi = min(tree[rt<<1].mi, tree[rt<<1|1].mi);
    tree[rt].value = tree[rt<<1].value + tree[rt<<1|1].value;
}

void build(int l, int r, int rt)
{
    tree[rt].l = l;
    tree[rt].r = r;
    tree[rt].lazy = 0;
    if(l == r) {
        scanf("%I64d", &tree[rt].b);
        tree[rt].value = 0;
        tree[rt].mi = tree[rt].b;
        return;
    }
    int m = tree[rt].mid();
    build(lson);
    build(rson);
    pushup(rt);
}
void update(int l, int r, int rt, ll add)
{
    if(tree[rt].l == l && tree[rt].r == r || add == 0) {
        tree[rt].lazy += add;
        tree[rt].mi -= add;
        if(tree[rt].mi > 0) {
            return;
        }
        else if(l != r) {
            pushdown(rt);
            update(l, tree[rt].mid(), rt<<1, 0);
            update(tree[rt].mid()+1, r, rt<<1|1, 0);
            pushup(rt);
            return;
        }
    }
    if(tree[rt].l == tree[rt].r) {
        if(tree[rt].mi <= 0) {
            tree[rt].mi = tree[rt].b;
            tree[rt].value++;
        }
        return;
    }
    pushdown(rt);
    int m = tree[rt].mid();
    if(r<=m) update(l, r, rt<<1, add);
    else if(l > m) update(l, r, rt<<1|1, add);
    else {
        update(l, m, rt<<1, add);
        update(m+1,r,rt<<1|1, add);
    }
    pushup(rt);
}

ll query(int l, int r, int rt)
{
    if(l == tree[rt].l&&r == tree[rt].r) {
        return tree[rt].value;
    }
    pushdown(rt);
    int m = tree[rt].mid();
    ll res = 0;
    if(r <= m) res+=query(l, r, rt<<1);
    else if(l > m) res+=query(l, r, rt <<1|1);
    else {
        res+=query(lson);
        res+=query(rson);
    }
    return res;
}
int main()
{
    int n, q;
    while(scanf("%d%d", &n, &q)!=EOF)
    {
        build(1, n, 1);
        char str[20];
        int l, r;
        for(int i = 0; i < q; i++)
        {
            scanf("%s%d%d", str, &l, &r);
            if(str[0] == 'a') {
                update(l, r, 1, 1);
            }
            else {
                printf("%I64d\n", query(l, r, 1));
            }
        }
    }
    return 0;
}

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值