「LOJ 6308」「雅礼国庆 2017 Day1」Mod

LOJ传送门

这道题居然让我想到了 jury_2 的集训队论文,其实确实还是有异曲同工之妙的。

Solution

用线段树维护区间和以及区间最大值

对于操作 1 ,直接 Query 查询区间和;
对于操作 2 ,假设当前为区间为 [l,r] ,若 max{Ai|i[l,r]}<x ,则直接返回,否则分别递归到左右儿子 [l,mid][mid+1,r] ,直到 l=r ,对 x 取模后返回,更新区间;
对于操作 3 ,直接 Updata 单点修改。

复杂度为 O((m+n)lognlogw) w 为权值。

Proof

首先是操作 1,3 ,显然 O(mlogn)

接着是操作 2 ,分析一下取模的性质: i mod x<i2 ,这个性质很显然。

于是对于数 ai ,我们最多将其修改 O(logai) 次,每次修改为 O(logn)
由于原数列有 n 个数以及操作 3 至多增加 m 个数,所以总的复杂度为 O((m+n)lognlogw)

总的来说这还是一道不错的套路题。

#include <cstdio>
#define Max(_A, _B) (_A > _B ? _A : _B)
#define R register
const int MaxN = 100010;
int a[MaxN], B[1 << 18]; long long S[1 << 18];
void Build(R int node, R int begin, R int end)
{
    if(begin == end)
    {
        S[node] = B[node] = a[begin];
        return ;
    }
    R int mid = begin + end >> 1;
    Build(node << 1, begin, mid);
    Build(node << 1 | 1, mid + 1, end);
    S[node] = S[node << 1] + S[node << 1 | 1];
    B[node] = Max(B[node << 1], B[node << 1 | 1]);
}
long long Query(R int node, R int begin, R int end, R int l, R int r)
{
    if(l <= begin && end <= r) return S[node];
    R int mid = begin + end >> 1;
    R long long t1 = 0, t2 = 0;
    if(l <= mid) t1 = Query(node << 1, begin, mid, l, r);
    if(r > mid) t2 = Query(node << 1 | 1, mid + 1, end, l, r);
    return t1 + t2;
}
void Updata(R int node, R int begin, R int end, R int pos, R int val)
{
    if(begin == end)
    {
        S[node] = B[node] = val;
        return ;
    }
    R int mid = begin + end >> 1;
    if(pos <= mid) Updata(node << 1, begin, mid, pos, val);
    else Updata(node << 1 | 1, mid + 1, end, pos, val);
    S[node] = S[node << 1] + S[node << 1 | 1];
    B[node] = Max(B[node << 1], B[node << 1 | 1]);
}
void Modify(R int node, R int begin, R int end, R int l, R int r, R int val)
{
    if(B[node] < val) return ;
    if(l <= begin && end <= r)
    {
        if(begin == end) S[node] = B[node] = S[node] % val;
        else 
        {
            R int mid = begin + end >> 1;
            if(B[node << 1] >= val) Modify(node << 1, begin, mid, l, r, val);
            if(B[node << 1 | 1] >= val) Modify(node << 1 | 1, mid + 1, end, l, r, val);
            S[node] = S[node << 1] + S[node << 1 | 1];
            B[node] = Max(B[node << 1], B[node << 1 | 1]);
        }
        return ;
    }
    R int mid = begin + end >> 1;
    if(l <= mid) Modify(node << 1, begin, mid, l, r, val);
    if(r > mid) Modify(node << 1 | 1, mid + 1, end, l, r, val);
    S[node] = S[node << 1] + S[node << 1 | 1];
    B[node] = Max(B[node << 1], B[node << 1 | 1]);
}
int main()
{
    R int n, m;
    scanf("%d %d", &n, &m);
    for(R int i = 1; i <= n; i++) scanf("%d", &a[i]);
    Build(1, 1, n);
    while(m--)
    {
        R int opt;
        scanf("%d", &opt);
        if(opt == 1)
        {
            R int l, r;
            scanf("%d %d", &l, &r);
            printf("%lld\n", Query(1, 1, n, l, r));
        }
        if(opt == 2)
        {
            R int l, r, x;
            scanf("%d %d %d", &l, &r, &x);
            Modify(1, 1, n, l, r, x);
        }
        if(opt == 3)
        {
            R int k, x;
            scanf("%d %d", &k, &x);
            Updata(1, 1, n, k, x);
        }
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/steaunk/article/details/79734391