[BZOJ4373]算术天才⑨与等差数列
[BZOJ4373]算术天才⑨与等差数列
BZOJ
标准的做法似乎是线段树维护原数组的最大最小值,差分数组的gcd以及pre数组的最大值
pre表示上一个与该数值相同的下标(然后这个修改我不太会,好像是用个set搞一搞)
那么蒟蒻用一种更快的方法过掉此题
可以线段树维护最小值以及平方和和立方和(对大质数取模)
我只能说这样非常难卡,非常非常难卡,如果有hack数据欢迎下方评论
\[a_1^2+(a_1+d)^2+...+[a_1+(n-1)d]^2=na_1^2+n(n-1)a_1d+\frac{n(n-1)(2n-1)}{6}d^2
\]
\[a_1^3+(a_1+d)^3+...+[a_1+(n-1)d]^3=na_1^3+\frac{3n(n-1)a_1^2d}{2}+\frac{n(n-1)(2n-1)a_1d^2}{2}+\frac{n^2(n-1)^2}{4}d^3
\]
#define ll long long
#define ls x<<1,l,mid
#define rs x<<1|1,mid+1,r
#include<bits/stdc++.h>
using namespace std;
const int _=3e5+5,p=1e9+7;
int re(){
int x=0,w=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
return x*w;
}
int n,m,yes,Mn,S2,S3,inv2=500000004,inv4=250000002,inv6=166666668;
int mn[_<<2],s2[_<<2],s3[_<<2];
inline int js2(ll s,ll x,ll d){
return ((x*s%p*s%p+x*(x-1)%p*s%p*d%p)%p+
(x*(x-1)%p*(2*x-1)%p*inv6%p*d%p*d%p)%p)%p;
}
inline int js3(ll s,ll x,ll d){
return ((x*s%p*s%p*s%p+x*(x-1)*inv2%p*3%p*s%p*s%p*d%p)%p+
(x*(x-1)%p*inv2%p*(2*x-1)%p*s%p*d%p*d%p+
x*x%p*(x-1)%p*(x-1)%p*inv4%p*d%p*d%p*d%p)%p)%p;
}
inline void in(int x,int v){
mn[x]=v;s2[x]=1ll*v*v%p;s3[x]=1ll*v*v%p*v%p;
}
inline void pu(int x){
int L=x<<1,R=x<<1|1;
mn[x]=min(mn[L],mn[R]);
s2[x]=(s2[L]+s2[R])%p;s3[x]=(s3[L]+s3[R])%p;
}
void bu(int x,int l,int r){
if(l==r){in(x,re());return;}
int mid=(l+r)>>1;bu(ls);bu(rs);pu(x);
}
void upd(int x,int l,int r,int k,int v){
if(l==r){in(x,v);return;}
int mid=(l+r)>>1;if(k<=mid)upd(ls,k,v);
else upd(rs,k,v);pu(x);
}
void q(int x,int l,int r,int ql,int qr){
if(ql<=l&&r<=qr){
Mn=min(Mn,mn[x]);S2=(S2+s2[x])%p;
S3=(S3+s3[x])%p;return;
}
int mid=(l+r)>>1;if(ql<=mid)q(ls,ql,qr);
if(qr>mid)q(rs,ql,qr);
}
int main(){
n=re(),m=re();bu(1,1,n);
int op,x,y,k;
while(m--){
op=re(),x=re()^yes,y=re()^yes;
if(op==1)upd(1,1,n,x,y);
else{
Mn=1e9+1;S2=S3=0;
k=re()^yes;q(1,1,n,x,y);
ll sum2=js2(Mn,y-x+1,k);
ll sum3=js3(Mn,y-x+1,k);
if((sum2==S2&&sum3==S3)||y-x==0){yes++;puts("Yes");}
else puts("No");
}
}
return 0;
}