hdu 6315 Naive Operations(线段树区间整除区间)

题意:
给出一个长度为 n n n初值为0的a数组,以及长度为 n n n b b b数组,b数组是开始给出的固定的。
接下来 q q q次操作, a d d ( l , r ) add(l,r) add(l,r) 使得数组a区间 [ l , r ] [l,r] [l,r]所有元素+1,或者查询 ∑ i = l r a [ i ] b [ i ] \sum^{r}_{i=l}{\frac{a[i]}{b[i]}} i=lrb[i]a[i]
思路:
区间操作一般就用线段树来维护。
很容易想到加完后暴力求区间和,但不用写就知道肯定TLE,这时候如果反向思考,线段树维护b区间最小值min,区间和sum,对于每次add操作,区间最小值减一,若最小值为0的话,则sum++(在这有个操作,来降低复杂度,降低了很多,就是如果min>1的话,对当前区间打懒标记,继续往下更新,如果min==1,直接更新到叶节点,然后min回复当前区间最小值,sum++,懒标记为0)
别的操作就是正常线段树,很好写,主要是维护b区间最小值来模拟加操作降低复杂度难以想到,总的复杂度 O ( n l o g n 2 ) O(nlog{n}^2) O(nlogn2)

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N = 1e5 + 10;
int n, q;
ll k;
char str[30];
struct node {
    ll s, v, mi, lz;
} t[N << 2];
void pushup(int rt) {
    t[rt].mi = min(t[rt << 1].mi, t[rt << 1 | 1].mi);
    t[rt].s = t[rt << 1].s + t[rt << 1 | 1].s;
}
void pushdown(int rt) {
    if(t[rt].lz) {
        t[rt << 1].lz += t[rt].lz;
        t[rt << 1 | 1].lz += t[rt].lz;
        t[rt << 1].mi -= t[rt].lz;
        t[rt << 1 | 1].mi -= t[rt].lz;
        t[rt].lz = 0;
    }
}
void build(int l, int r, int rt) {
    t[rt].s = t[rt].lz = 0;
    if(l == r) {
        scanf("%lld", &k);
        t[rt].v = t[rt].mi = k;
        return;
    }
    int m = l + r >> 1;
    build(l, m, rt << 1);
    build(m + 1, r, rt << 1 | 1);
    pushup(rt);
}
void update(int l, int r, int rt, int L, int R) {
    if(L <= l && r <= R && t[rt].mi > 1) {
        t[rt].mi--;
        t[rt].lz++;
        return;
    }
    if(l == r && t[rt].mi == 1) {
        t[rt].mi = t[rt].v;
        t[rt].lz = 0;
        t[rt].s++;
        return;
    }
    pushdown(rt);
    int m = l + r >> 1;
    if(m >= L)
        update(l, m, rt << 1, L, R);
    if(m < R)
        update(m + 1, r, rt << 1 | 1, L, R);
    pushup(rt);
}
ll query(int l, int r, int rt, int L, int R) {
    if(L <= l && r <= R)
        return t[rt].s;
    ll ans = 0, m = l + r >> 1;
    pushdown(rt);
    if(m >= L)
        ans += query(l, m, rt << 1, L, R);
    if(m < R)
        ans += query(m + 1, r, rt << 1 | 1, L, R);
    return ans;
}
int main() {
    while(~scanf("%d%d", &n, &q)) {
        build(1, n, 1);
        for(int l, r, i = 1; i <= q; i++) {
            scanf("%s%d%d", str, &l, &r);
            if(str[0] == 'a')
                update(1, n, 1, l, r);
            else
                printf("%lld\n", query(1, n, 1, l, r));
        }
    }
    return 0;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值