BZOJ 4373 算术天才⑨与等差数列 线段树 set 维护区间最值/GCD
算术天才⑨与等差数列
Description
算术天才⑨非常喜欢和等差数列玩耍。
有一天,他给了你一个长度为 $ n $ 的序列,其中第 $ i $ 个数为 $ a[i] $ 。
他想考考你,每次他会给出询问 $ l,r,k $ ,问区间 $ [l,r] $ 内的数从小到大排序后能否形成公差为 $ k $ 的等差数列。
当然,他还会不断修改其中的某一项。
为了不被他鄙视,你必须要快速并正确地回答完所有问题。
注意:只有一个数的数列也是等差数列。
Input
第一行包含两个正整数 $ n,m(1 \le n,m \le 300000) $ ,分别表示序列的长度和操作的次数。
第二行包含 $ n $ 个整数,依次表示序列中的每个数 $ ai $ 。
接下来 $ m $ 行,每行一开始为一个数 $ op $ ,
若 $ op=1 $ ,则接下来两个整数 $ x,y(1 \le x \le n,0 \le y \le 10^9) $ ,表示把 $ a[x] $ 修改为 $ y $ 。
若 $ op=2 $ ,则接下来三个整数 $ l,r,k(1 \le l \le r \le n,0 \le k \le 10^9) $ ,表示一个询问。
在本题中,$ x,y,l,r,k $ 都是经过加密的,都需要异或你之前输出的Yes的个数来进行解密。
Output
输出若干行,对于每个询问,如果可以形成等差数列,那么输出Yes,否则输出No。
Sample Input
5 3
1 3 2 5 6
2 1 5 1
1 5 4
2 1 5 1
Sample Output
No
Yes
思路
- 直接维护区间等差数列显然很难,那么考虑一下:
如果区间 $ [l,r] (l<r) $ 排序后能形成公差为 $ k (k>0) $ 的等差数列,要满足什么条件?
1.很显然,假设 $ min $ 是区间最小值, $ max $ 是区间最大值,那么 $ min+k(r-l)=max $
2.区间相邻两个数之差的绝对值的 $ gcd=k $
3.区间没有重复的数
-
前两个条件 线段树直接维护就好了→_→
-
第三个条件:
-
对于每个权值开个 $ set $ ,值为位置(离散化标号)
-
然后维护一个 $ pre[i] $ 表示当前 $ a[i] $ 这个值,在 $ i $ 前面最后一次出现的位置。
那么满足第 $ 3 $ 个条件,当且仅当区间 $ [l,r] $ 的 $ pre $ 最大值小于 $ l $ 。这个也是用线段树维护。 -
然后看修改操作:在 $ set $ 上找到前一个数、后一个数,然后修改相应的值。
代码
/**************************************************************
Problem: 4373
User: PotremZ
Language: C++
Result: Accepted
Time:9300 ms
Memory:80920 kb
****************************************************************/
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<set>
#include<map>
using namespace std;
#define int long long
#define N 300005
inline int read() {
register char ch;
while(!isdigit(ch=getchar()));
register int x=ch^'0';
while(isdigit(ch=getchar())) x=(((x<<2)+x)<<1)+(ch^'0');
return x;
}
set<int> s[N<<1];
set<int>::iterator it;
map<int,int> mp;
int smx[N<<2],smn[N<<2],sgd[N<<2],spr[N<<2];
int n,m,pre[N],yescnt,a[N],tot,nxt,prv,nxtp,prvp;
int resmax,resmin,resgcd,respre;
int gcd(int x,int y){ return y==0 ? x : gcd(y,x%y); }
inline void pushup(int o,int mid){
smx[o]=max(smx[o<<1],smx[o<<1|1]);
smn[o]=min(smn[o<<1],smn[o<<1|1]);
spr[o]=max(spr[o<<1],spr[o<<1|1]);
sgd[o]=gcd(abs(a[mid+1]-a[mid]),gcd(sgd[o<<1],sgd[o<<1|1]));
}
void build(int o,int l,int r){
if(l==r){
smx[o]=smn[o]=a[l];
spr[o]=pre[l];
sgd[o]=0;
return;
}
int mid=l+r>>1;
build(o<<1,l,mid); build(o<<1|1,mid+1,r);
pushup(o,mid);
}
void updata(int o,int l,int r,int x){
if(l==r){
smx[o]=smn[o]=a[l];
spr[o]=pre[l];
sgd[o]=0;
return;
}
int mid=l+r>>1;
if(x>mid) updata(o<<1|1,mid+1,r,x);
else updata(o<<1,l,mid,x);
pushup(o,mid);
}
void query(int o,int l,int r,int L,int R){
if(L<=l&&r<=R){
resmax=smx[o]; resmin=smn[o]; resgcd=sgd[o]; respre=spr[o];
return;
}
int mid=l+r>>1;
if(L>mid) query(o<<1|1,mid+1,r,L,R);
else if(R<=mid) query(o<<1,l,mid,L,R);
else {
query(o<<1,l,mid,L,R);
int tmpmax=resmax,tmpmin=resmin,tmpgcd=resgcd,tmppre=respre;
query(o<<1|1,mid+1,r,L,R);
resmax=max(resmax,tmpmax);
resmin=min(resmin,tmpmin);
resgcd=gcd(abs(a[mid+1]-a[mid]),gcd(resgcd,tmpgcd));
respre=max(respre,tmppre);
}
}
signed main(){
n=read(); m=read();
for(int i=1;i<=n;++i){
a[i]=read();
if(mp.count(a[i])){
it=s[mp[a[i]]].end();
pre[i]=*(--it);
s[mp[a[i]]].insert(i);
} else {
mp[a[i]]=++tot;
s[tot].insert(i);
}
}
build(1,1,n);
while(m--){
int opt=read();
if(opt==1){
int x=(read()^yescnt),y=(read()^yescnt);
if(x<1||x>n||a[x]==y) continue;
s[mp[a[x]]].erase(x);
it=s[mp[a[x]]].upper_bound(x);
if(it==s[mp[a[x]]].end()) nxt=n+1; else nxt=*it;
if(it==s[mp[a[x]]].begin()) prv=0; else prv=*(--it);
if(!mp.count(y)) mp[y]=++tot;
it=s[mp[y]].upper_bound(x);
if(it==s[mp[y]].end()) nxtp=n+1; else nxtp=*it;
if(it==s[mp[y]].begin()) prvp=0; else prvp=*(--it);
s[mp[y]].insert(x);
a[x]=y;
pre[x]=prvp;
updata(1,1,n,x);
if(nxt<=n){
pre[nxt]=prv;
updata(1,1,n,nxt);
}
if(nxtp<=n){
pre[nxtp]=x;
updata(1,1,n,nxtp);
}
} else {
int L=read()^yescnt,R=read()^yescnt,k=read()^yescnt;
if(L>R||L<1||R>n||R<1||L>n){
puts("No");
continue;
}
if(L==R){
puts("Yes");
++yescnt;
continue;
}
query(1,1,n,L,R);
if(resmax==resmin){
if(k==0){
puts("Yes");
++yescnt;
}
else puts("No");
continue;
}
else if(resmax-resmin!=1ll*k*(R-L)||resgcd!=k||respre>=L) puts("No");
else {
puts("Yes");
++yescnt;
}
}
}
return 0;
}