HDU 5828 Rikka with Sequence(线段树)

101 篇文章 0 订阅
74 篇文章 0 订阅

题目链接:点击打开链接

思路:

对于该题, 由于存在区间加一个值, 那么所有数都可能永远不会变成1, 但是数与数之间的相对值会趋近于相等。  比如1 2 3 4 5, 进行一次根号操作变成1 1 1 2 2, 而一旦如果相等, 那么他们同时加一个数也是相等的。  所以我们增加一个标记bit[rt]表示该区间内的数是否全部相等,如果相等等于什么。

细节参见代码:

#include <cstdio>
#include <cstring>
#include <iostream>
#include <cmath>
#define lson l, m, rt<<1
#define rson m+1, r, rt<<1|1
using namespace std;
typedef long long LL;
const int maxn = 100010;
LL sum[maxn<<2], add[maxn<<2];
int n, m, vv, bit[maxn<<2];
inline void PushDown(int rt,int m) {
       if (add[rt]) {
              add[rt<<1] += add[rt];
              add[rt<<1|1] += add[rt];
              if(bit[rt<<1]) bit[rt<<1] += add[rt];
              if(bit[rt<<1|1]) bit[rt<<1|1] += add[rt];

              sum[rt<<1] += add[rt] * (m - (m >> 1));
              sum[rt<<1|1] += add[rt] * (m >> 1);
              add[rt] = 0;
       }
}
inline void PushUp(int rt) {
    sum[rt] = sum[rt<<1] + sum[rt<<1|1];
    if(bit[rt<<1] == bit[rt<<1|1] && bit[rt<<1] && bit[rt<<1|1]) bit[rt] = bit[rt<<1];
    else bit[rt] = 0;
    return ;
}
inline void build(int l, int r, int rt) {
    sum[rt] = 0;
    add[rt] = 0;
    bit[rt] = 0;
    if(l == r) {
        scanf("%d", &vv);
        sum[rt] = vv;
        bit[rt] = vv;
        return ;
    }
    int m = (l+r)>>1;
    build(lson);
    build(rson);
    PushUp(rt);
}
inline void update(int L, int R, int l, int r, int rt) {
    if(L<=l && r<=R && bit[rt]) {
        LL res = sqrt(bit[rt] + 0.5);
        add[rt] -= bit[rt] - res;
        sum[rt] = (LL)(r - l + 1) * res;
        bit[rt] = res;
        return ;
    }
    if(l == r) {
        sum[rt] = sqrt(sum[rt] + 0.5);
        return ;
    }
    int m = (l+r)>>1;
    PushDown(rt , r - l + 1);
    if(L <= m) update(L, R, lson);
    if(m < R) update(L, R, rson);
    PushUp(rt);
}
inline void update2(int L,int R,int c,int l,int r,int rt) {
       if (L <= l && r <= R) {
            add[rt] += c;
            if(bit[rt]) bit[rt] += c;
            sum[rt] += (LL)c * (r - l + 1);
            return ;
       }
       PushDown(rt , r - l + 1);
       int m = (l + r) >> 1;
       if (L <= m) update2(L , R , c , lson);
       if (m < R) update2(L , R , c , rson);
       PushUp(rt);
}
inline LL query(int L, int R, int l, int r, int rt) {
    if(L <= l && r <= R) {
        return sum[rt];
    }
    int m = (l+r)>>1;
    PushDown(rt , r - l + 1);
    LL ans = 0;
    if(L <= m) ans += query(L, R, lson);
    if(m < R) ans += query(L, R, rson);
    return ans;
}
int id[maxn], l[maxn], r[maxn], v[maxn];

int main() {
    int T;
    scanf("%d", &T);
    while(T--) {
        scanf("%d", &n);

        scanf("%d", &m);
        build(1, n, 1);
        int last = -1;
        for(int i = 1; i <= m; i++) {
            scanf("%d%d%d", &id[i], &l[i], &r[i]);
            if(l[i] > r[i]) swap(l[i], r[i]);
            if(id[i] == 1) scanf("%d", &v[i]);
            if(id[i] == 3) last = i;
        }
        for(int i = 1; i <= m; i++) {
            if(last < i) break;
            if(id[i] == 1) {
                update2(l[i], r[i], v[i], 1, n, 1);
            }
            else if(id[i] == 2) {
                update(l[i], r[i], 1, n, 1);
            }
            else {
                printf("%I64d\n", query(l[i], r[i], 1, n, 1));
            }
        }
    }
    return 0;
}


评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值