BZOJ4373 : 算术天才⑨与等差数列
设$pre[i]$表示第$i$个数上一次出现的位置,$d[i]=abs(a[i]-a[i+1])$。
用线段树维护区间内$a$的最小值、最大值,$pre$的最大值以及$d$的$\gcd$。
对于询问$l\ r\ k$,首先特判掉$l=r$或者$k=0$的情况。
然后求出区间最小值和最大值、以及$pre$的最大值,判断最值是否合法以及$pre$是否都小于$l$。
如果都满足,那么继续查询$[l,r-1]$里所有$d$的$\gcd$,如果$\gcd$是$k$的倍数,那么就可行。
时间复杂度$O(n\log n)$。
#include<cstdio> #include<cstdlib> #include<map> #include<set> #include<algorithm> using namespace std; const int N=300010,M=1050000; int n,m,cnt,i,op,x,y,z,a[N],b[N],c[N],d[N],K; int vmi[M],vma[M],vp[M],vd[M],mi,ma,flag,g; map<int,int>id; set<int>T[N<<1]; set<int>::iterator pre,nxt; inline void read(int&a){char c;while(!(((c=getchar())>='0')&&(c<='9')));a=c-'0';while(((c=getchar())>='0')&&(c<='9'))(a*=10)+=c-'0';} inline int abs(int x){return x>0?x:-x;} inline int gcd(int a,int b){ if(!a)return b; if(!b)return a; return __gcd(a,b); } inline int getid(int x){ int&t=id[x]; if(t)return t; t=++cnt; T[t].insert(0),T[t].insert(n+1); return t; } void build(int x,int a,int b){ if(a==b){ vmi[x]=vma[x]=::a[a]; vp[x]=c[a]; vd[x]=d[a]; return; } int mid=(a+b)>>1; build(x<<1,a,mid),build(x<<1|1,mid+1,b); vmi[x]=min(vmi[x<<1],vmi[x<<1|1]); vma[x]=max(vma[x<<1],vma[x<<1|1]); vp[x]=max(vp[x<<1],vp[x<<1|1]); vd[x]=gcd(vd[x<<1],vd[x<<1|1]); } void changep(int x,int a,int b,int c,int p){ if(a==b){ vp[x]=p; return; } int mid=(a+b)>>1; if(c<=mid)changep(x<<1,a,mid,c,p);else changep(x<<1|1,mid+1,b,c,p); vp[x]=max(vp[x<<1],vp[x<<1|1]); } void change(int x,int a,int b,int c,int v,int p){ if(a==b){ vmi[x]=vma[x]=v; vp[x]=p; return; } int mid=(a+b)>>1; if(c<=mid)change(x<<1,a,mid,c,v,p);else change(x<<1|1,mid+1,b,c,v,p); vmi[x]=min(vmi[x<<1],vmi[x<<1|1]); vma[x]=max(vma[x<<1],vma[x<<1|1]); vp[x]=max(vp[x<<1],vp[x<<1|1]); } void changed(int x,int a,int b,int c,int p){ if(a==b){ vd[x]=p; return; } int mid=(a+b)>>1; if(c<=mid)changed(x<<1,a,mid,c,p);else changed(x<<1|1,mid+1,b,c,p); vd[x]=gcd(vd[x<<1],vd[x<<1|1]); } void ask(int x,int a,int b,int c,int d){ if(c<=a&&b<=d){ mi=min(mi,vmi[x]); ma=max(ma,vma[x]); if(vp[x]>=c)flag=1; return; } int mid=(a+b)>>1; if(c<=mid)ask(x<<1,a,mid,c,d); if(d>mid)ask(x<<1|1,mid+1,b,c,d); } void askd(int x,int a,int b,int c,int d){ if(c<=a&&b<=d){ g=gcd(g,vd[x]); return; } int mid=(a+b)>>1; if(c<=mid)askd(x<<1,a,mid,c,d); if(d>mid)askd(x<<1|1,mid+1,b,c,d); } inline bool query(int x,int y,int z){ if(x==y)return 1; mi=1000000000,ma=flag=g=0; ask(1,1,n,x,y); if(!z)return mi==ma; if(flag)return 0; if(1LL*(y-x)*z+mi!=ma)return 0; askd(1,1,n,x,y-1); return g%z==0; } int main(){ read(n),read(m); for(i=1;i<=n;i++){ read(a[i]); T[b[i]=getid(a[i])].insert(i); pre=T[b[i]].find(i); c[i]=*(--pre); } for(i=1;i<n;i++)d[i]=abs(a[i]-a[i+1]); build(1,1,n); while(m--){ read(op),read(x),read(y);x^=K,y^=K; if(op==1){ pre=nxt=T[b[x]].find(x); pre--,nxt++; if(*nxt<n)changep(1,1,n,*nxt,*pre); T[b[x]].erase(x); b[x]=getid(y); T[b[x]].insert(x); pre=nxt=T[b[x]].find(x); pre--,nxt++; if(*nxt<n)changep(1,1,n,*nxt,x); change(1,1,n,x,a[x]=y,*pre); if(x>1)changed(1,1,n,x-1,abs(a[x-1]-y)); if(x<n)changed(1,1,n,x,abs(y-a[x+1])); }else{ read(z); if(query(x,y,z^K))K++,puts("Yes");else puts("No"); } } return 0; }