zoukankan      html  css  js  c++  java
  • 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;
    }
    
  • 相关阅读:
    栅格系统
    JQuery
    week 4
    week 1
    js嵌套,BOM,DOM,内置对象,数组,自定义对象,正则表达式
    week 2
    case when的两种用法
    获取当前路径
    parse,tryparse区别
    parse ,tryparse 续
  • 原文地址:https://www.cnblogs.com/PotremZ/p/BZOJ4373.html
Copyright © 2011-2022 走看看