【CF438D】 The Child and Sequence 线段树取模

The Child and Sequence

题目概述

给你一串数字,支持一下几种操作

  1. 区间和查询
  2. 区间取模
  3. 单点修改

题目链接

传送门

分析

显然是线段树,应为没有区间修改这类的操作,我们于是省去了一个懒标签和pushdown的操作,关键是如何取模,这里维护了一个区间最大值,如果最大值小于模的化直接返回,相当于做了一些局部优化,数字还挺多,建议快读。

代码

#include <iostream>
#include <algorithm>
#include <cctype>
#include <cstdio>
#define mid (l + r >> 1)

using namespace std;
typedef long long ll;
const int N = 1e5 + 10;
int n, q;

inline int read(){
   int x = 0, op = 1;
   char ch = getchar();
    while (!isdigit(ch)){
        if (ch == '-') op = -1;
        ch = getchar();
    }
    while (isdigit(ch)){
        x = (x << 1) + (x << 3) + (ch ^ 48);
        ch = getchar();
    }
    return x * op;
}

ll sum[N << 2], Max[N << 2];

inline void push_up(int i){
    sum[i] = sum[i << 1] + sum[i << 1|1];
    Max[i] = max(Max[i << 1], Max[i << 1|1]);
}

inline void buildTree(int i, int l, int r){
    if (l == r){
        sum[i] = Max[i] = read();
        return;
    }

    buildTree(i << 1, l, mid);
    buildTree(i << 1|1, mid + 1, r);
    push_up(i);
}

inline void modify_point(int i, int l, int r, int pos, ll val){
    if (l == r){
        sum[i] = Max[i] = val;
        return;
    }

    if (pos <= mid)
        modify_point(i << 1, l, mid, pos, val);
    else
        modify_point(i << 1|1, mid + 1, r, pos, val);

    push_up(i);
}

inline void modify_mod(int i, int l, int r, int crtl, int crtr, int mod){
    if (Max[i] < mod)
        return;
    if (l == r){
        sum[i] %= mod;
        Max[i] %= mod;
        return;
    }

    if (mid >= crtl)
        modify_mod(i << 1, l, mid, crtl, crtr, mod);
    if (mid < crtr)
        modify_mod(i << 1|1, mid + 1, r, crtl ,crtr, mod);

    push_up(i);
}

inline ll query_interval(int i, int l, int r, int crtl, int crtr){
    if (l > crtr || r < crtl)
        return 0;

    if (l >= crtl && r <= crtr)
        return sum[i];

    ll ans = 0;
    if (mid >= crtl)
        ans += query_interval(i << 1, l, mid, crtl, crtr);
    if (mid < crtr)
        ans += query_interval(i << 1|1, mid + 1, r, crtl, crtr);
    return ans;
}

int main() {
    n = read(), q = read();
    buildTree(1, 1, n);
    int op, a, b, c;
    while (q--){
        op = read();
        a = read(), b = read();
        if (op == 1){
            printf("%lld\n", query_interval(1, 1, n, a, b));
        }else if (op == 2){
            c = read();
            modify_mod(1, 1, n, a, b, c);
        }else{
            modify_point(1, 1, n, a, b);
        }
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值