码迷,mamicode.com
首页 > 其他好文 > 详细

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

时间:2020-04-25 00:49:28      阅读:50      评论:0      收藏:0      [点我收藏+]

标签:child   ref   就是   div   否则   problems   log   时间复杂度   证明   

题目链接: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} \rfloor$<2,那么x%mod=x-$\lfloor \frac{x}{mod} \rfloor$*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\n", 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(线段树)

标签:child   ref   就是   div   否则   problems   log   时间复杂度   证明   

原文地址:https://www.cnblogs.com/zzzzzzy/p/12770961.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!