求你们查错,我都做了两天了,不想浪费你们的时间,可是我实在ac不了,两种思路都30分wa,麻烦帮我分别查一下错,或者每个程序给我找一个小数据可以手算的反例,谢谢(提交时没有freopen)
第1份代码的思路是在每一次下放标记之前先将标记的左右儿子下放,防止加法和乘法撞车。然后当遇到边界时在打标记前先下放原有的标记。
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
#define ll long long
ll sumv[400010],lazytagadd[400010],lazytagmul[400010],a[100010];
const ll p=571373;
inline void pushup(const int&o){
sumv[o]=(sumv[o<<1]%p+sumv[o<<1|1]%p)%p;
}
inline void build(const int&o,const int&l,const int&r){
lazytagadd[o]=0;
lazytagmul[o]=1;
if(l==r){
sumv[o]=a[l]%p;
return;
}
int mid=(l+r)>>1;
build(o<<1,l,mid);
build(o<<1|1,mid+1,r);
pushup(o);
}
inline void pushdown(const int&o,const int&l,const int&r){
if(l==r){
lazytagadd[o]=0;
lazytagmul[o]=1;
return;
}
int mid=(l+r)>>1;
sumv[o<<1]=((sumv[o<<1]%p)+((lazytagadd[o]%p)*((mid-l+1)%p))%p)%p;
sumv[o<<1|1]=(sumv[o<<1|1]%p+((lazytagadd[o]%p)*((r-mid)%p))%p)%p;
lazytagadd[o<<1]=(lazytagadd[o<<1]%p+lazytagadd[o]%p)%p;
lazytagadd[o<<1|1]=(lazytagadd[o<<1|1]%p+lazytagadd[o]%p)%p;
lazytagadd[o]=0;
sumv[o<<1]=((sumv[o<<1]%p)*(lazytagmul[o]%p))%p;
sumv[o<<1|1]=((sumv[o<<1|1]%p)*(lazytagmul[o]%p))%p;
lazytagmul[o<<1]=((lazytagmul[o<<1]%p)*(lazytagmul[o]%p))%p;
lazytagmul[o<<1|1]=((lazytagmul[o<<1|1]%p)*(lazytagmul[o]%p))%p;
lazytagmul[o]=1;
}
inline void change(const int&o,const int&l,const int&r,const int&ql,const int&qr,const ll&v,const int&mode){
if(ql<=l&&qr>=r){
if(mode){
pushdown(o,l,r);
lazytagadd[o]=(lazytagadd[o]%p+v%p)%p;
sumv[o]=(sumv[o]%p+((v%p)*((r-l+1)%p)%p))%p;
// pushdown(o,l,r);
return;
}else{
pushdown(o,l,r);
lazytagmul[o]=((lazytagmul[o]%p)*(v%p))%p;
sumv[o]=((sumv[o]%p)*(v%p))%p;
// pushdown(o,l,r);
return;
}
}
int mid=(l+r)>> 1;
pushdown(o<<1,l,mid);
pushdown(o<<1|1,mid+1,r);
pushdown(o,l,r);
if(ql<=mid){
change(o<<1,l,mid,ql,qr,v,mode);
}
if(qr>mid){
change(o<<1|1,mid+1,r,ql,qr,v,mode);
}
pushup(o);
}
inline ll querys(const int&o,const int&l,const int&r,const int&ql,const int&qr){
if(ql<=l&&qr>=r){
// pushdown(o,l,r);
return sumv[o]%p;
}
int mid=(l+r)>>1;
pushdown(o<<1,l,mid);
pushdown(o<<1|1,mid+1,r);
pushdown(o,l,r);
ll ans=0;
if(ql<=mid){
ans+=querys(o<<1,l,mid,ql,qr)%p;
}
if(qr>mid)ans+=querys(o<<1|1,mid+1,r,ql,qr)%p;
return ans%p;
}
int main(){
freopen("t4.in","r",stdin);
freopen("t4.out","w",stdout);
memset(sumv,0,sizeof sumv);
int n,m;
cin>>n>>m;
cin>>a[1];
if(!m)return 0;
for(int i=1;i<=n;++i)cin>>a[i];
build(1,1,n);
while(m--){
int opt;
cin>>opt;
if(opt==1){
int x,y;
ll k;
cin>>x>>y>>k;
change(1,1,n,x,y,k,0);
}else if(opt==2){
int x,y;
ll k;
cin>>x>>y>>k;
change(1,1,n,x,y,k,1);
}else{
int x,y;
cin>>x>>y;
cout<<querys(1,1,n,x,y)%p<<endl;
}
}
return 0;
}
第二份代码的思路是当遇到边界打标记时,如果是加法则直接打标记,如果是乘法,那么加法标记/乘法标记/sumv都乘上v
而下放时不进行优先级处理,直接先乘后加
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define ll long long
ll a[1000100],sumv[4000100],lazytagadd[4000010],lazytagmul[4000010];
const int p=571373;
inline void pushup(const int&o){
sumv[o]=(sumv[o<<1]%p+sumv[o<<1|1]%p)%p;
}
inline void build(const int&o,const int&l,const int&r){
lazytagadd[o]=0;
lazytagmul[o]=1;
if(l==r){
sumv[o]=a[l]%p;
return;
}
int mid=(l+r)>>1;
build(o<<1,l,mid);
build(o<<1|1,mid+1,r);
pushup(o);
}
inline void pushdown(const int&o,const int&l,const int&r){
if(l==r){
lazytagadd[o]=0;
lazytagmul[o]=1;
return;
}
int mid=(l+r)>>1;
lazytagadd[o<<1]=lazytagadd[o<<1]%p+lazytagadd[o]%p;
lazytagadd[o<<1]%=p;
lazytagadd[o<<1|1]=lazytagadd[o<<1|1]%p+lazytagadd[o]%p;
lazytagadd[o<<1|1]%=p;
lazytagmul[o<<1]=lazytagmul[o<<1]%p*(lazytagmul[o]%p);
lazytagmul[o<<1]%=p;
lazytagmul[o<<1|1]=lazytagmul[o<<1|1]%p*(lazytagmul[o]%p);
lazytagmul[o<<1|1]%=p;
sumv[o<<1]=sumv[o<<1]%p*(lazytagmul[o]%p);
sumv[o<<1]%=p;
sumv[o<<1|1]=sumv[o<<1|1]%p*(lazytagmul[o]%p);
sumv[o<<1|1]%=p;
sumv[o<<1]=sumv[o<<1]%p+(lazytagadd[o]%p*((mid-l+1)%p))%p;
sumv[o<<1]%=p;
sumv[o<<1|1]=sumv[o<<1|1]%p+(lazytagadd[o]%p*((r-mid)%p))%p;
sumv[o<<1|1]%=p;
lazytagadd[o]=0;
lazytagmul[o]=1;
}
inline void change(const int &o,const int&l,const int&r,const int&ql,const int&qr,const ll&v,const int&mode){
if(ql<=l&&qr>=r){
if(!mode){
lazytagmul[o]=lazytagmul[o]%p*(v%p);
lazytagmul[o]%=p;
lazytagadd[o]=lazytagadd[o]%p*(v%p);
lazytagadd[o]%=p;
sumv[o]=sumv[o]%p*(v%p);
sumv[o]%=p;
// sumv[o]=sumv[o]%p+(lazytagadd[o]%p*((v-1)%p)*(r-l+1))%p;
// sumv[o]%=p;
}else{
lazytagadd[o]=lazytagadd[o]%p+v%p;
lazytagadd[o]%=p;
sumv[o]=sumv[o]%p+(v%p*((r-l+1)%p))%p;
sumv[o]%=p;
}
return;
}
pushdown(o,l,r);
int mid=(l+r)>>1;
if(ql<=mid)change(o<<1,l,mid,ql,qr,v,mode);
if(qr>mid)change(o<<1|1,mid+1,r,ql,qr,v,mode);
pushup(o);
}
inline ll querys(const int &o,const int&l,const int&r,const int&ql,const int&qr){
if(ql<=l&&qr>=r){
return sumv[o]%p;
}
ll ans=0;
pushdown(o,l,r);
int mid=(l+r)>>1;
if(ql<=mid)ans+=querys(o<<1,l,mid,ql,qr)%p;
if(qr>mid)ans+=querys(o<<1|1,mid+1,r,ql,qr)%p;
return ans%p;
}
int main(){
freopen("t4.in","r",stdin);
freopen("t4.out","w",stdout);
memset(sumv,0,sizeof sumv);
int n,m;
cin>>n>>m;
cin>>a[1];
for(int i=1;i<=n;++i)cin>>a[i];
build(1,1,n);
while(m--){
int op;
cin>>op;
if(op==1){
int x,y;
ll k;
cin>>x>>y>>k;
change(1,1,n,x,y,k,0);
}else if(op==2){
int x,y;
ll k;
cin>>x>>y>>k;
change(1,1,n,x,y,k,1);
}else{
int x,y;
cin>>x>>y;
cout<<querys(1,1,n,x,y)%p<<endl;
}
}
return 0;
}
另外,麻烦大佬帮我解释一下为什么题解里pushdown都是把add标记乘上mul标记
我个人认为在边界 时已经这么处理了,下放时再这么做就重复了。