牛牛的等差数列

题目链接:牛牛的等差数列


对每个区间维护首项和公差即可。显然是具有可加性的。

最开始分块TLE了。

(比赛的时候L写成1了。。。。)


AC代码:

#pragma GCC optimize("-Ofast","-funroll-all-loops")
#include
#define int long long
#define mid (l+r>>1)
using namespace std;
const int N=2e5+10;
const int mod=3LL*5*7*11*13*17*19*23;
const int inv=mod-mod/2;
int n,a[N],q;
char *fs,*ft,buf[1<<20];
#define gc() (fs==ft&&(ft=(fs=buf)+fread(buf,1,1<<20,stdin),fs==ft))?0:*fs++;
inline int read(){
    int x=0,f=1; char ch=gc();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=gc();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=gc();}
    return x*f;
}
int calc(int a,int d,int len){
    return (a*len%mod+(len-1)*len*inv%mod*d%mod)%mod;
}
struct seg{
	int sum[N<<2],k[N<<2],d[N<<2];
	void build(int p,int l,int r){
		if(l==r){sum[p]=a[l]; return ;}
		build(p<<1,l,mid),build(p<<1|1,mid+1,r);
		sum[p]=(sum[p<<1]+sum[p<<1|1])%mod;
	}
	void push_down(int p,int l,int r){
		if(!k[p]&&!d[p])	return ;
		k[p<<1]=(k[p<<1]+k[p])%mod,d[p<<1]=(d[p<<1]+d[p])%mod;
		k[p<<1|1]=(k[p<<1|1]+k[p]+(mid-l+1)*d[p]%mod)%mod,d[p<<1|1]=(d[p<<1|1]+d[p])%mod;
		sum[p<<1]=(sum[p<<1]+calc(k[p],d[p],mid-l+1))%mod;
		sum[p<<1|1]=(sum[p<<1|1]+calc((k[p]+(mid-l+1)*d[p]%mod)%mod,d[p],r-mid))%mod;
		k[p]=0,d[p]=0;
	}
	void change(int p,int l,int r,int ql,int qr,int qk,int qd){
		if(l==ql&&r==qr){
			k[p]=(k[p]+qk)%mod,d[p]=(d[p]+qd)%mod;
			sum[p]=(sum[p]+calc(qk,qd,r-l+1))%mod;
			return ;
		}
		push_down(p,l,r);
		if(qr<=mid) change(p<<1,l,mid,ql,qr,qk,qd);
		else if(ql>mid) change(p<<1|1,mid+1,r,ql,qr,qk,qd);
		else{
			change(p<<1,l,mid,ql,mid,qk,qd);
			change(p<<1|1,mid+1,r,mid+1,qr,((mid-ql+1)*qd%mod+qk)%mod,qd);
		}
		sum[p]=(sum[p<<1]+sum[p<<1|1])%mod;
	}
	int ask(int p,int l,int r,int ql,int qr){
		if(l==ql&&r==qr)	return sum[p];
		push_down(p,l,r);
		if(qr<=mid)	return ask(p<<1,l,mid,ql,qr);
		else if(ql>mid)	return ask(p<<1|1,mid+1,r,ql,qr);
		else return (ask(p<<1,l,mid,ql,mid)+ask(p<<1|1,mid+1,r,mid+1,qr))%mod;
	}
}t;
signed main(){
	n=read();
	for(int i=1;i<=n;i++)	a[i]=read();
	t.build(1,1,n);
	q=read();
	for(int i=1,op,l,r,val,d;i<=q;i++){
		op=read(),l=read(),r=read(),val=read();
		if(op==1){
			d=read();	t.change(1,1,n,l,r,val,d);
		}else{
			printf("%lld\n",t.ask(1,1,n,l,r)%val);
		}
	}
	return 0;
}

你可能感兴趣的:(线段树)