Codeforces Round #250 (Div. 1) - D. The Child and Sequence(线段树)

Posted zzzzzzy

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Codeforces Round #250 (Div. 1) - D. The Child and Sequence(线段树)相关的知识,希望对你有一定的参考价值。

题目链接:The Child and Sequence

题意:给你你一个序列a,有三种操作:(1)求$sum_{i=l}^{r}a[i]$,(2)让区间[l,r]内的所有数模x,(3)令a[k]=x

思路:如果没有操作(2),那就是线段树模板题,现在考虑如何实现操作(2)

定理:如果mod<x,那么x%mod<$frac{x}{2}$

证明:假设mod<$frac{x}{2}$,那么就肯定有x%mod<mod<$frac{x}{2}$,如果$frac{x}{2}$<mod<x,则有1<$lfloor frac{x}{mod} floor$<2,那么x%mod=x-$lfloor frac{x}{mod} floor$*mod<$frac{x}{2}$

那么对于操作(2),一个数最多被取模logn次,所以我们可以用线段树再维护一个区间的最大值,如果最大值小于mod,则可以减枝,否则则继续递归,直到到叶子节点,此时直接取模即可,总的时间复杂度仍然为O(nlogn)

#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>

using namespace std;

typedef long long ll;

const int N = 100010;

struct node {
    int l, r;
    ll v, imax;
};

int n, m;
ll c[N];
node tr[4 * N];

void build(int k, int l, int r)
{
    tr[k].l = l, tr[k].r = r;
    if (l == r) {
        tr[k].v = tr[k].imax = c[l];
        return;
    }
    int mid = (l + r) / 2;
    build(2 * k, l, mid);
    build(2 * k + 1, mid + 1, r);
    tr[k].v = tr[2 * k].v + tr[2 * k + 1].v;
    tr[k].imax = max(tr[2 * k].imax, tr[2 * k + 1].imax);
}

void update(int k, int x, ll v)
{
    if (tr[k].l == tr[k].r) {
        tr[k].v = tr[k].imax = v;
        return;
    }
    int mid = (tr[k].l + tr[k].r) / 2;
    if (x <= mid) update(2 * k, x, v);
    else update(2 * k + 1, x, v);
    tr[k].v = tr[2 * k].v + tr[2 * k + 1].v;
    tr[k].imax = max(tr[2 * k].imax, tr[2 * k + 1].imax);
}

ll ask(int k, int a, int b)
{
    if (tr[k].l >= a && tr[k].r <= b) return tr[k].v;
    int mid = (tr[k].l + tr[k].r) / 2;
    ll res = 0;
    if (a <= mid) res += ask(2 * k, a, b);
    if (b > mid) res += ask(2 * k + 1, a, b);
    return res;
}

void cmod(int k, int a, int b, ll mod)
{
    if (tr[k].imax < mod) return;
    if (tr[k].l == tr[k].r) {
        tr[k].v %= mod;
        tr[k].imax = tr[k].v;
        return;
    }
    int mid = (tr[k].l + tr[k].r) / 2;
    if (a <= mid) cmod(2 * k, a, b, mod);
    if (b > mid) cmod(2 * k + 1, a, b, mod);
    tr[k].v = tr[2 * k].v + tr[2 * k + 1].v;
    tr[k].imax = max(tr[2 * k].imax, tr[2 * k + 1].imax);
}

int main()
{
    scanf("%d%d", &n, &m);
    for (int i = 1; i <= n; i++) scanf("%lld", &c[i]);
    build(1, 1, n);
    while (m--) {
        int k;
        scanf("%d", &k);
        if (1 == k) {
            int a, b;
            scanf("%d%d", &a, &b);
            printf("%lld
", ask(1, a, b));
        }
        else if (2 == k) {
            int a, b;
            ll x;
            scanf("%d%d%lld", &a, &b, &x);
            cmod(1, a, b, x);
        }
        else {
            int a;
            ll x;
            scanf("%d%lld", &a, &x);
            update(1, a, x);
        }
    }
    return 0;
}

 

以上是关于Codeforces Round #250 (Div. 1) - D. The Child and Sequence(线段树)的主要内容,如果未能解决你的问题,请参考以下文章

BZOJ3625 [Codeforces Round #250]小朋友和二叉树

bzoj3625 [Codeforces Round #250]小朋友和二叉树

[bzoj3625][Codeforces Round #250]小朋友和二叉树

Codeforces Round #250 (Div. 2) A - The Child and Homework

Codeforces Round #250 (Div. 1) - D. The Child and Sequence(线段树)

Codeforces Round #250 (Div. 1)E. The Child and Binary Tree