神奇脑洞题解——苦恼的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() { ; }
顺带一提,LINYIN有妹子啦!!!
完结撒花!!!