大佬求助
查看原帖
大佬求助
240374
hicode_002楼主2021/7/23 22:52

求你们查错,我都做了两天了,不想浪费你们的时间,可是我实在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标记

我个人认为在边界 时已经这么处理了,下放时再这么做就重复了。

2021/7/23 22:52
加载中...