BZOJ 4373: 算术天才⑨与等差数列 线段树
Description
算术天才⑨非常喜欢和等差数列玩耍。
有一天,他给了你一个长度为n的序列,其中第i个数为a[i]。
他想考考你,每次他会给出询问l,r,k,问区间[l,r]内的数从小到大排序后能否形成公差为k的等差数列。
当然,他还会不断修改其中的某一项。
为了不被他鄙视,你必须要快速并正确地回答完所有问题。
注意:只有一个数的数列也是等差数列。
Input
第一行包含两个正整数n,m(1<=n,m<=300000),分别表示序列的长度和操作的次数。
第二行包含n个整数,依次表示序列中的每个数a[i](0<=a[i]<=10^9)。
接下来m行,每行一开始为一个数op,
若op=1,则接下来两个整数x,y(1<=x<=n,0<=y<=10^9),表示把a[x]修改为y。
若op=2,则接下来三个整数l,r,k(1<=l<=r<=n,0<=k<=10^9),表示一个询问。
在本题中,x,y,l,r,k都是经过加密的,都需要异或你之前输出的Yes的个数来进行解密。
Output
输出若干行,对于每个询问,如果可以形成等差数列,那么输出Yes,否则输出No。
题解:
公差 $k$ 和区间长度都是固定的,所以等差数列也是唯一确定的.
这里分几个情况:
$l=r$,无限制条件.
$k=0$,所有数必须都相同.
其他情况,令区间最大值为 $Max$,最小值为 $Min$,那么 $Max-Min=(len-1)\times k$
除此之外,还需满足没有数字重复出现,任意两个数的差都是 $k$ 的倍数
这里分几个情况:
$l=r$,无限制条件.
$k=0$,所有数必须都相同.
其他情况,令区间最大值为 $Max$,最小值为 $Min$,那么 $Max-Min=(len-1)\times k$
除此之外,还需满足没有数字重复出现,任意两个数的差都是 $k$ 的倍数
#include <cstdio> #include <string> #include <cstring> #include <algorithm> #include <map> #include <set> #define ll long long using namespace std; namespace IO { #define rint register int void setIO(string s) { string in=s+".in",out=s+".out"; freopen(in.c_str(),"r",stdin); freopen(out.c_str(),"w",stdout); } inline int read(){ rint x=0,f=1;char ch=getchar(); while (ch<'0' || ch>'9'){if (ch=='-')f=-1;ch=getchar();} while ('0'<=ch && ch<='9')x=(x<<1)+(x<<3)+(ch^48),ch=getchar(); return x*f; } }; const int maxn=300006; const int inf=1000000002; int n,m; int arr[maxn],brr[maxn]; int GCD(int a,int b) { return b?GCD(b,a%b):a; } namespace A { int minv[maxn<<2],maxv[maxn<<2]; void pushup(int l,int r,int now) { int mid=(l+r)>>1; minv[now]=minv[now<<1]; maxv[now]=maxv[now<<1]; if(r>mid) { minv[now]=min(minv[now],minv[now<<1|1]); maxv[now]=max(maxv[now],maxv[now<<1|1]); } } void build(int l,int r,int now) { if(l==r) { minv[now]=maxv[now]=arr[l]; return; } int mid=(l+r)>>1; build(l,mid,now<<1); if(r>mid) build(mid+1,r,now<<1|1); pushup(l,r,now); } void update(int l,int r,int now,int p,int v) { if(l==r) { minv[now]=maxv[now]=v; return; } int mid=(l+r)>>1; if(p<=mid) update(l,mid,now<<1,p,v); else update(mid+1,r,now<<1|1,p,v); pushup(l,r,now); } int qmax(int l,int r,int now,int L,int R) { if(l>=L&&r<=R) return maxv[now]; int mid=(l+r)>>1,re=0; if(mid>=L) re=max(re,qmax(l,mid,now<<1,L,R)); if(R>mid) re=max(re,qmax(mid+1,r,now<<1|1,L,R)); return re; } int qmin(int l,int r,int now,int L,int R) { if(l>=L&&r<=R) return minv[now]; int mid=(l+r)>>1,re=inf; if(mid>=L) re=min(re,qmin(l,mid,now<<1,L,R)); if(R>mid) re=min(re,qmin(mid+1,r,now<<1|1,L,R)); return re; } }; namespace lst { int id; int lst[maxn<<2]; map<int,int>idx; set<int>S[maxn<<1]; set<int>::iterator it; void insert(int v,int i) { if(!idx[v]) idx[v]=++id; int cur=idx[v]; S[cur].insert(i); } void pushup(int l,int r,int now) { int mid=(l+r)>>1; lst[now]=lst[now<<1]; if(r>mid) lst[now]=max(lst[now],lst[now<<1|1]); } void build(int l,int r,int now) { if(l==r) { int cur=idx[arr[l]]; it=S[cur].lower_bound(l); if(it==S[cur].begin()) lst[now]=-inf; else { it--; lst[now]=(*it); } return; } int mid=(l+r)>>1; if(l<=mid) build(l,mid,now<<1); if(r>mid) build(mid+1,r,now<<1|1); pushup(l,r,now); } void update(int l,int r,int now,int p) { if(l==r) { int cur=idx[arr[l]]; it=S[cur].lower_bound(l); if(it==S[cur].begin()) lst[now]=-inf; else { it--; lst[now]=(*it); } return; } int mid=(l+r)>>1; if(p<=mid) update(l,mid,now<<1,p); else update(mid+1,r,now<<1|1,p); pushup(l,r,now); } int query(int l,int r,int now,int L,int R) { if(l>=L&&r<=R) return lst[now]; int mid=(l+r)>>1,re=0; if(L<=mid) re=max(re, query(l,mid,now<<1,L,R)); if(R>mid) re=max(re, query(mid+1,r,now<<1|1,L,R)); return re; } void modify(int v,int i) { if(!idx[v]) idx[v]=++id; int cur=idx[v]; S[idx[arr[i]]].erase(i); it=S[idx[arr[i]]].lower_bound(i+1); if(it!=S[idx[arr[i]]].end()) { update(1,n,1,(*it)); } S[cur].insert(i), arr[i]=v; update(1,n,1,i); } }; namespace delta { int gc[maxn<<2]; void pushup(int l,int r,int now) { int mid=(l+r)>>1; gc[now]=gc[now<<1]; if(r>mid) gc[now]=GCD(gc[now<<1|1],gc[now]); } void build(int l,int r,int now) { if(l==r) { gc[now]=brr[l]; return; } int mid=(l+r)>>1; if(l<=mid) build(l,mid,now<<1); if(r>mid) build(mid+1,r,now<<1|1); pushup(l,r,now); } void update(int l,int r,int now,int p,int v) { if(l==r) { gc[now]=v; return; } int mid=(l+r)>>1; if(p<=mid) update(l,mid,now<<1,p,v); else update(mid+1,r,now<<1|1,p,v); pushup(l,r,now); } int query(int l,int r,int now,int L,int R) { if(l>=L&&r<=R) return gc[now]; int mid=(l+r)>>1,re=0; if(L<=mid) re=query(l,mid,now<<1,L,R); if(R>mid) re=re?GCD(re,query(mid+1,r,now<<1|1,L,R)):query(mid+1,r,now<<1|1,L,R); return re; } }; int main() { using namespace IO; // IO::setIO("input"); int i,j; n=read(),m=read(); for(i=1;i<=n;++i) { arr[i]=read(); lst::insert(arr[i],i); } for(i=1;i<=n;++i) brr[i]=abs(arr[i+1]-arr[i]); A::build(1,n,1); delta::build(1,n-1,1); lst::build(1,n,1); int cc=0; int h=0; for(int cas=1;cas<=m;++cas) { int op=read(); if(op==1) { int x,y; x=read(),y=read(),x^=cc,y^=cc; if(arr[x]==y) continue; lst::modify(y,x); A::update(1,n,1,x,y); if(x==1) delta::update(1,n-1,1,1,abs(arr[2]-arr[1])); else if(x==n) delta::update(1,n-1,1,n-1,abs(arr[n]-arr[n-1])); else { delta::update(1,n-1,1,x-1,abs(arr[x]-arr[x-1])); delta::update(1,n-1,1,x,abs(arr[x+1]-arr[x])); } } if(op==2) { int l,r,k; l=read(),r=read(),k=read(); l^=cc,r^=cc,k^=cc; if(l==r) printf("Yes\n"),++cc; else if(k==0) { if(A::qmin(1,n,1,l,r)==A::qmax(1,n,1,l,r)) printf("Yes\n"),++cc; else printf("No\n"); } else { int len=r-l; int minn=A::qmin(1,n,1,l,r), maxx=A::qmax(1,n,1,l,r); int flag=0; if(maxx-minn==1ll*k*len) { if(lst::query(1,n,1,l,r)>=l) flag=1; else { if(delta::query(1,n-1,1,l,r-1)%k) flag=1; else { printf("Yes\n"), ++cc; } } } else flag=1; if(flag) printf("No\n"); } } } return 0; }