题目大意:给你一个序列和一些操作,让你实现这些操作,并回答询问。具体操作见题目。
解题思路:因为输入的东西需要xor之前输出的yes个数,所以本题是强制在线。
一个序列形成等差数列必须满足以下三个条件:
1.序列最小数+公差*(项数-1)=序列最大数;
2.该区间差分后的gcd=公差;
3.数字各不相等。
前两个条件用线段树就可以轻松维护,第三个条件貌似需要用一些神奇的方法。
然而这题可以维护平方和,2、3条件就可以忽略了。
不过平方和会很大,甚至超过long long,要进行取模,而且平方和公式里有个除以6,还要用什么逆元。
于是就有dalao用int,让它自然溢出,在维护平方和时直接乘6,完美解决了上面的问题。orz orz orz
等差数列平方和公式(L,等差数列长度;d,公差)$a_1 ^2 L+a_1dL(L-1)+\frac{d^2 L(L-1)(2L-1)}{6}$
于是我用了此dalao的方法,此题就AC了。
C++ Code:
#include<cstdio>
#include<algorithm>
#include<cctype>
using namespace std;
char buf[10000020];
int bufpos;
inline void init(){
buf[fread(buf,1,10000020,stdin)]='\0';
bufpos=0;
}
inline int readint(){
int p=0;
for(;!isdigit(buf[bufpos]);bufpos++);
for(;isdigit(buf[bufpos]);bufpos++)
p=p*10+buf[bufpos]-'0';
return p;
}
struct Node{
int sum,Min;
Node():sum(0),Min(2000000000){}
Node operator +(const Node& rhs)const{
Node s;
s.sum=sum+rhs.sum;
s.Min=min(rhs.Min,Min);
return s;
}
}d[1100003];
int n,m,yes=0,x,y,l,r,k;
inline void update(int cur){
d[cur].Min=min(d[cur<<1].Min,d[cur<<1|1].Min);
d[cur].sum=d[cur<<1].sum+d[cur<<1|1].sum;
}
void make(int l,int r,int cur){
if(l==r){
d[cur].Min=readint();
d[cur].sum=d[cur].Min*d[cur].Min*6;
return;
}
int mid=l+r>>1;
make(l,mid,cur<<1);
make(mid+1,r,cur<<1|1);
update(cur);
}
void change(int l,int r,int cur,int x,int y){
if(l==r){
d[cur].Min=y;
d[cur].sum=y*y*6;
return;
}
int mid=l+r>>1;
if(x<=mid)change(l,mid,cur<<1,x,y);else
change(mid+1,r,cur<<1|1,x,y);
update(cur);
}
Node query(int l,int r,int cur,int L,int R){
if(L<=l&&r<=R)return d[cur];
int mid=l+r>>1;
Node ans;
if(L<=mid)ans=query(l,mid,cur<<1,L,R);
if(mid<R)ans=ans+query(mid+1,r,cur<<1|1,L,R);
return ans;
}
int main(){
init();
n=readint(),m=readint();
make(1,n,1);
for(;m--;){
int op=readint();
if(op==1){
x=readint()^yes,y=readint()^yes;
change(1,n,1,x,y);
}else{
l=readint()^yes,r=readint()^yes,k=readint()^yes;
int len=r-l+1;
Node p=query(1,n,1,l,r);
if(p.sum==p.Min*p.Min*len*6+p.Min*k*len*(len-1)*6+k*k*len*(len-1)*(2*len-1)){
puts("Yes");
yes++;
}else puts("No");
}
}
return 0;
}