神奇脑洞题解——苦恼的Van

传送门

一句话题面:给定一个序列,维护两种操作。区间取模和区间求和。

这道题不能使用Lazy标记!!!

不是不用,是不能!!!

mod运算不满足分配律,因此无法使用Lazy标记。

但是如果单纯只写一个区间求值和一mod到底的mod操作,会T到你怀疑人生。

虽然mod不满足分配律,但是mod有一个性质:如果x<mod,那么x%mod==x

由此,我们可以维护一个区间最大值,以此来判断这个区间是否需要进行mod运算。

AC代码:

#include<iostream>
#include<cstdio>
using namespace std;
int sum[400001],mx[400001];
int n,m,a,b,c;
int val[100001];
int ls(int x)
{
    return x<<1;
}
int rs(int x)
{
    return x<<1|1;
}
void pushup(int x)
{
    sum[x]=sum[ls(x)]+sum[rs(x)];
    mx[x]=max(mx[ls(x)],mx[rs(x)]);
}
void build(int x,int l,int r)
{
    if(l==r)
    {
        sum[x]=val[l];
        mx[x]=sum[x];
        return ;
    }
    int mid=(l+r)>>1;
    build(ls(x),l,mid);
    build(rs(x),mid+1,r);
    pushup(x); 
}
void Mod(int x,int l,int r,int nl,int nr,int mod)
{
    if(l==r)
    {
        sum[x]%=mod;
        mx[x]%=mod;
        return;
    }
    if(mx[x]<mod)
        return;
    int mid=(l+r)>>1;
    if(nl<=mid)
        Mod(ls(x),l,mid,nl,nr,mod);
    if(nr>mid)
        Mod(rs(x),mid+1,r,nl,nr,mod);
    pushup(x);
}
int Query(int x,int l,int r,int nl,int nr)
{
    if(nl<=l&&nr>=r)
        return sum[x];
    int mid=(l+r)>>1;
    int res=0;
    if(nl<=mid)
    {
        res+=Query(ls(x),l,mid,nl,nr);
    }
    if(nr>mid)
    {
        res+=Query(rs(x),mid+1,r,nl,nr);
    }
    return res;
}
int LINYIN()
{
    freopen("van_modify.in","r",stdin);
    freopen("van_modify.out","w",stdout);
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&val[i]);
    }
    build(1,1,n);
    for(int i=1;i<=m;i++)
    {
        scanf("%d",&a);
        if(a==0)
        {
            scanf("%d%d",&a,&b);
            printf("%d",Query(1,1,n,a,b));
        }
        else
        {
            scanf("%d%d%d",&a,&b,&c);
            Mod(1,1,n,a,b,c);
        }
    }
    return 0;
}
int LWH=LINYIN();
int main()
{
    ;
}
AC

顺带一提,LINYIN有妹子啦!!!

完结撒花!!!

原文地址:https://www.cnblogs.com/XLINYIN/p/11663191.html