题意:一个序列,两种操作:1.单点修改 2.查询[l,r]内的数由小到大排序后能否形成公差k的等差数列
1<=n,m<=300000,0<=a[i]<=10^9,强制在线
正解是这么说的。。。若能形成公差为k的等差数列则:1.最大值=最小值+(r-l)*k ,2.相邻两数之差都为k的倍数 ,3.没有重复元素
第一个好维护,第二个差分后维护,由于公共gcd从下到上是单调不增的所以均摊log,关键在于第三个。
用set求出每个元素i后面第一个和它相等的元素nex[i],判断[l,r]中的最小nex是否>r即可。
然而注意公差为0要特判,上面这种“不能有重复元素”的判断方法就挂了。。。
l==r也要特判。
然而还有单点修改,第一个第二个也好改,为了维护第三个,每个元素除了记录nex,还要记录前面最近的相等元素pre,修改时像双向链表那样pre->nex=nex,nex->pre=pre就好,新的pre->nex=nex->pre=this。这个过程中涉及到的点都要去线段树里更新信息。
这题还有一种哈希做法。差分后实际上就是比较一个集合是否是k,2k,3k…(n-1)k,分别维护一段区间的和与平方和(由于很大所以需要取模),比较是否与预期相等即可。
平方和公式:,由于有/6,维护时直接乘以6,就可以该取模取模了。
我写的是第一种。
#ifdef ONLINE_JUDGE
#define NDEBUG
#define null_type null_mapped_type
#endif
#include
#include
#define gm 1<<20
using namespace __gnu_pbds;
typedef std::pair<int,int> pr;
typedef tree set;
set s;
inline int __gcd(int a,int b)
{
int c;
while(b) c=a,a=b,b=c%b;
return a;
}
int n,m;
int gcd[gm],las[gm],minn[gm],maxx[gm];
inline int max(int a,int b){return ainline int min(int a,int b){return ainline int abs(int x){return x<0?-x:x;}
int val[300002],pre[300002],nex[300002],cf[300002],pos[300002];
void segtree(int l=1,int r=n,int o=1)
{
if(l==r)
{
gcd[o]=cf[l];
las[o]=nex[l];
minn[o]=maxx[o]=val[l];
pos[l]=o;
return;
}
int mid=l+r>>1,ls=o<<1,rs=ls|1;
segtree(l,mid,ls);
segtree(mid+1,r,rs);
gcd[o]=__gcd(gcd[ls],gcd[rs]);
las[o]=min(las[ls],las[rs]);
minn[o]=min(minn[ls],minn[rs]);
maxx[o]=max(maxx[ls],maxx[rs]);
}
inline void modify(int x)
{
int o=pos[x],ls,rs;
gcd[o]=cf[x],minn[o]=maxx[o]=val[x],las[o]=nex[x];
while(o>>=1)
{
ls=o<<1,rs=ls|1;
gcd[o]=__gcd(gcd[ls],gcd[rs]);
las[o]=min(las[ls],las[rs]);
minn[o]=min(minn[ls],minn[rs]);
maxx[o]=max(maxx[ls],maxx[rs]);
}
}
inline void modify_cf(int x)
{
int o=pos[x];
gcd[o]=cf[x];
while(o>>=1)
gcd[o]=__gcd(gcd[o<<1],gcd[(o<<1)|1]);
}
inline void modify_nex(int x)
{
int o=pos[x];
las[o]=nex[x];
while(o>>=1)
las[o]=min(las[o<<1],las[(o<<1)|1]);
}
inline void change_val(int x,int v)
{
int l,r;
s.erase(pr(val[x],x));
cf[x]+=v-val[x],cf[x+1]+=val[x]-v;
if(x1);
val[x]=v;
l=pre[x],r=nex[x];
nex[l]=r,pre[r]=l;
if(l) modify_nex(l);
set::iterator a=s.upper_bound(pr(val[x],x)),b=a;
--a;
l=a->first==v?a->second:0,r=b->first==v?b->second:n+1;
nex[l]=pre[r]=x;
if(l) modify_nex(l);
pre[x]=l,nex[x]=r;
s.insert(pr(val[x],x));
modify(x);
}
int get_l,get_r;
int get_gcd,get_las,get_minn,get_maxx;
void get(int l=1,int r=n,int o=1)
{
if(get_l<=l&&r<=get_r)
{
get_las=min(las[o],get_las);
get_minn=min(minn[o],get_minn);
get_maxx=max(maxx[o],get_maxx);
return;
}
int mid=l+r>>1,ls=o<<1,rs=ls|1;
if(get_l<=mid) get(l,mid,ls);
if(mid1,r,rs);
}
void __get_gcd(int l=1,int r=n,int o=1)
{
if(get_l<=l&&r<=get_r)
{
get_gcd=__gcd(gcd[o],get_gcd);
return;
}
int mid=l+r>>1,ls=o<<1,rs=ls|1;
if(get_l<=mid) __get_gcd(l,mid,ls);
if(mid1,r,rs);
}
int cnt=0;
inline const char* check(int x,int y,int k)
{
if(x==y) return ++cnt,"Yes";
get_gcd=0,get_las=n+1,get_minn=0x7fffffff,get_maxx=-1;
get_l=x,get_r=y;
get();
if(!k) return get_minn==get_maxx?(++cnt,"Yes"):"No";
if(get_las<=y) return "No";
if(get_maxx!=get_minn+(long long)(y-x)*k) return "No";
get_l=x+1;
__get_gcd();
return abs(get_gcd)==k?(++cnt,"Yes"):"No";
}
int op,x,y,k;
int main()
{
scanf("%d%d",&n,&m);
s.insert(pr(0,0));
s.insert(pr(0x7fffffff,n+1));
for(int i=1;i<=n;++i)
scanf("%d",val+i),s.insert(pr(val[i],i)),cf[i]=val[i]-val[i-1];
for(int i=1;i<=n;++i)
{
set::iterator a=s.find(pr(val[i],i)),b=a;
--a;++b;
pre[i]=a->first==val[i]?a->second:0;
nex[i]=b->first==val[i]?b->second:n+1;
}
segtree();
for(int i=1;i<=m;++i)
{
scanf("%d%d%d",&op,&x,&y);
x^=cnt,y^=cnt;
if(op==1)
change_val(x,y);
else
{
scanf("%d",&k);
k^=cnt;
puts(check(x,y,k));
}
}
return 0;
}