BZOJ 4373 算术天才⑨与等差数列 线段树 set 维护区间最值/GCD

$ Rightarrow $ 戳我进BZOJ原题

算术天才⑨与等差数列

Time Limit: 10 Sec quad Memory Limit: 128 MB
 

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;
}
原文地址:https://www.cnblogs.com/PotremZ/p/BZOJ4373.html