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

Description

给定一个长度为n的序列,支持区间取模、单点更新、区间求和三个操作

Solution

单点更新,区间求和显然可以用线段树直接肝,关键在于区间取模。
考虑线段树中除了存该区间的和,同时维护该区间的最大值,当模数大于最大值时,就不需要模了,否则进行单点取模。
注意,这里虽然是单点取模,但是不会TLE,因为对于每次取模操作,如果模数小于该数,则取模有效,该数最大只会变成 (n+1)/21 ( n + 1 ) / 2 − 1 ,然而每次只能对一个数直接赋值,所以这里最坏的时间复杂度是 O(mlog22n) O ( m l o g 2 2 n )

Code

#include
#include
#include
#include
#include
#include
#include
#include
#include
#define For(i , j , k) for (int i = (j) , _##end_ = (k) ; i <= _##end_ ; ++ i)
#define Fordown(i , j , k) for (int i = (j) , _##end_ = (k) ; i >= _##end_ ; -- i)
#define Set(a , b) memset(a , b , sizeof(a))
#define pb push_back
#define mp make_pair
#define lc (t << 1)
#define rc (t << 1 | 1)
#define mid ((l + r) >> 1)
#define INF (0x3f3f3f3f)
using namespace std;
typedef long long LL;
typedef pair<int , int> PII;

template <typename T> inline bool chkmax(T &a , T b) { return a < b ? (a = b , 1) : 0; }
template <typename T> inline bool chkmin(T &a , T b) { return b < a ? (a = b , 1) : 0; }

int _ , __;
char c_;
inline int read()
{
    for (_ = 0 , __ = 1 , c_ = getchar() ; !isdigit(c_) ; c_ = getchar()) if (c_ == '-') __ = -1;
    for ( ; isdigit(c_) ; c_ = getchar()) _ = (_ << 1) + (_ << 3) + (c_ ^ 48);
    return _ * __;
}

inline void file()
{
#ifndef ONLINE_JUDGE
    freopen("438D.in" , "r" , stdin);
    freopen("438D.out" , "w" , stdout);
#endif
}

const int maxn = 400001;

int n , m , maxv[maxn] , setv , x , y , Mod , type;
LL sumv[maxn];

inline void maintain(int t)
{
    maxv[t] = max(maxv[lc] , maxv[rc]);
    sumv[t] = sumv[lc] + sumv[rc];
}

void build(int t , int l , int r)
{
    if (l == r)
    {
        maxv[t] = sumv[t] = read();
        return ;
    }
    build(lc , l , mid);
    build(rc , mid + 1 , r);
    maintain(t);
}

void update_mod(int t , int l , int r)
{
    if (maxv[t] < Mod)
        return ;
    if (l == r)
    {
        maxv[t] = sumv[t] = sumv[t] % Mod;
        return ;
    }
    if (mid >= x)
        update_mod(lc , l , mid);
    if (mid < y)
        update_mod(rc , mid + 1 , r);
    maintain(t);
}

void update_set(int t , int l , int r)
{
    if (l == r)
    {
        maxv[t] = sumv[t] = setv;
        return ;
    }
    if (x <= mid)
        update_set(lc , l , mid);
    else
        update_set(rc , mid + 1 , r);
    maintain(t);
}

LL query(int t , int l , int r)
{
    if (x <= l && r <= y)
        return sumv[t];
    if (y <= mid)
        return query(lc , l , mid);
    if (x > mid)
        return query(rc , mid + 1 , r);
    return query(lc , l , mid) + query(rc , mid + 1 , r);
}

int main()
{
    file();
    n = read();
    m = read();
    build(1 , 1 , n);
    while (m --)
    {
        type = read();
        if (type == 1)
        {
            x = read();
            y = read();
            printf("%lld\n" , query(1 , 1 , n));
        }
        else
        if (type == 2)
        {
            x = read();
            y = read();
            Mod = read();
            update_mod(1 , 1 , n);
        }
        else
        {
            x = read();
            setv = read();
            update_set(1 , 1 , n);
        }
    }
    return 0;
}

你可能感兴趣的:(Codeforces,线段树)