• Codeforces Round #250 (Div. 1)


    题目链接: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;
    }
  • 相关阅读:
    Flash 全局安全性设置面板
    响应式布局的一个例子mark
    移动平台WEB前端开发技巧汇总
    自定义事件机制——观察者模式
    学习之响应式Web设计:Media Queries和Viewports
    常用栅格布局方案
    观察者模式的一个例子
    二进制文件转换为文本工具
    C#面向对象名词比较(二)
    MSN消息提示类
  • 原文地址:https://www.cnblogs.com/zzzzzzy/p/12770961.html
Copyright © 2020-2023  润新知