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;
}

  

posted @ 2016-01-08 19:01  Claris  阅读(1272)  评论(0编辑  收藏  举报