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;
    }
    
  • 相关阅读:
    vue form dynamic validator All In one
    TypeScript api response interface All In One
    closable VS closeable All In One
    macOS 如何开启 WiFi 热点 All In One
    vue css inline style All In One
    vs2010里面 新建网站里面的 asp.net网站 和 新建项目里面的 asp.net Web应用程序 的区别 (下)
    牛腩新闻 59 整合添加新闻页 FreeTextBox 富文本编辑器,检测到有潜在危险的 Request.Form 值,DropDownList 的使用
    牛腩新闻 61尾声: error.aspx的使用 防止报错
    vs2010里面 新建网站里面的 asp.net网站 和 新建项目里面的 asp.net Web应用程序 的区别 (上)
    牛腩新闻 62:尾声续2 asp.net的编译和发布
  • 原文地址:https://www.cnblogs.com/PotremZ/p/BZOJ4373.html
Copyright © 2011-2022 走看看