zoukankan      html  css  js  c++  java
  • 分块大法好

    新手推荐阅读:「分块」数列分块入门1 – 9 by hzwer

    练习:LibreOJ


     “大段维护,局部朴素”

    分块的调试检测技巧:

    可以生成一些大数据,然后用两份分块大小不同的代码来对拍,还可以根据运行时间尝试调整分块大小,减小常数。

     

    区间加法,单点查询

     1 #include<bits/stdc++.h>
     2 #define IL inline
     3 #define R register int
     4 #define ls(x) a[x].ch[0]
     5 #define rs(x) a[x].ch[1]
     6 #define fa(x) a[x].fa
     7 
     8 using namespace std;
     9 const int N=1e5+5,inf=0x3f3f3f3f;
    10 
    11 IL int read() {
    12     int f=1;char ch;
    13     while((ch=getchar())<'0'||ch>'9') if(ch=='-') f=-1;
    14     int res=ch-'0';
    15     while((ch=getchar())>='0'&&ch<='9') res=res*10+ch-'0';    
    16     return res*f;
    17 }
    18 
    19 int n,a[N],ad[N],b[N],len;
    20 
    21 IL void pre() {
    22     len=sqrt(n);
    23     for(R i=1;i<=n;++i) b[i]=(i-1)/len+1;
    24 }
    25 
    26 IL void add(int l,int r,int c) {
    27     for(R i=l;i<=min(r,b[l]*len);++i) a[i]+=c;
    28     if(b[l]!=b[r]) for(R i=(b[r]-1)*len+1;i<=r;++i) a[i]+=c;
    29     for(R i=b[l]+1;i<=b[r]-1;++i) ad[i]+=c;
    30 }
    31 
    32 IL void query(int x) {
    33     printf("%d
    ",a[x]+ad[b[x]]);
    34 }
    35 
    36 int main() {
    37     n=read();
    38     for(R i=1;i<=n;++i) a[i]=read();
    39     pre();
    40     for(R i=1;i<=n;++i) {
    41         int op=read(),l=read(),r=read(),c=read();
    42         if(!op) add(l,r,c);
    43         else query(r);
    44     }
    45     return 0;    
    46 }
    分块1

     

    区间加法,询问区间内小于某个值x的元素个数

    //vector

     1 #include<bits/stdc++.h>
     2 #define IL inline
     3 #define R register int
     4 #define ls(x) a[x].ch[0]
     5 #define rs(x) a[x].ch[1]
     6 #define fa(x) a[x].fa
     7 
     8 using namespace std;
     9 const int N=1e5+5,inf=0x3f3f3f3f;
    10 
    11 IL int read() {
    12     int f=1;char ch;
    13     while((ch=getchar())<'0'||ch>'9') if(ch=='-') f=-1;
    14     int res=ch-'0';
    15     while((ch=getchar())>='0'&&ch<='9') res=res*10+ch-'0';    
    16     return res*f;
    17 }
    18 
    19 int n,a[N],ad[N],b[N],len;
    20 vector<int> s[N];
    21 
    22 IL void pre() {
    23     len=sqrt(n);
    24     for(R i=1;i<=n;++i) b[i]=(i-1)/len+1,s[b[i]].push_back(a[i]);
    25     for(R i=1;i<=b[n];++i)sort(s[i].begin(),s[i].end());
    26 }
    27 
    28 IL void reset(int x) {
    29     s[x].clear();
    30     for(R i=(x-1)*len+1;i<=min(x*len,n);++i) s[x].push_back(a[i]);
    31     sort(s[x].begin(),s[x].end());
    32 }
    33 
    34 IL void add(int l,int r,int c) {
    35     for(R i=l;i<=min(r,b[l]*len);++i) a[i]+=c;reset(b[l]);
    36     if(b[l]!=b[r]) {
    37         for(R i=(b[r]-1)*len+1;i<=r;++i) a[i]+=c;
    38         reset(b[r]);
    39     }
    40     for(R i=b[l]+1;i<=b[r]-1;++i) ad[i]+=c;
    41 }
    42 
    43 IL void query(int l,int r,int x) {
    44     int ans=0;
    45     for(R i=l;i<=min(r,b[l]*len);++i) 
    46         if(a[i]+ad[b[i]]<x) ans++;
    47     if(b[l]!=b[r]) 
    48         for(R i=(b[r]-1)*len+1;i<=r;++i) 
    49             if(a[i]+ad[b[i]]<x) ans++;
    50     for(R i=b[l]+1;i<=b[r]-1;++i) ans+=lower_bound(s[i].begin(),s[i].end(),x-ad[i])-s[i].begin();
    51     printf("%d
    ",ans);
    52 }
    53 
    54 int main() {
    55     n=read();
    56     for(R i=1;i<=n;++i) a[i]=read();
    57     pre();
    58     for(R i=1;i<=n;++i) {
    59         int op=read(),l=read(),r=read(),c=read();
    60         if(!op) add(l,r,c);
    61         else query(l,r,c*c);
    62     }
    63     return 0;    
    64 }
    分块2

     

    区间加法,询问区间内小于某个值x的前驱(比其小的最大元素)

    //set

     1 #include<bits/stdc++.h>
     2 #define IL inline
     3 #define R register int
     4 #define ls(x) a[x].ch[0]
     5 #define rs(x) a[x].ch[1]
     6 #define fa(x) a[x].fa
     7 
     8 using namespace std;
     9 const int N=1e5+5,inf=0x3f3f3f3f;
    10 
    11 IL int read() {
    12     int f=1;char ch;
    13     while((ch=getchar())<'0'||ch>'9') if(ch=='-') f=-1;
    14     int res=ch-'0';
    15     while((ch=getchar())>='0'&&ch<='9') res=res*10+ch-'0';    
    16     return res*f;
    17 }
    18 
    19 int n,a[N],ad[N],b[N],len;
    20 set<int> s[N];
    21 
    22 IL void pre() {
    23     len=1000;
    24     for(R i=1;i<=n;++i) b[i]=(i-1)/len+1,s[b[i]].insert(a[i]);
    25 }
    26 
    27 IL void add(int l,int r,int c) {
    28     for(R i=l;i<=min(r,b[l]*len);++i) {
    29         s[b[i]].erase(a[i]);
    30         a[i]+=c;
    31         s[b[i]].insert(a[i]);
    32     }
    33     if(b[l]!=b[r]) 
    34         for(R i=(b[r]-1)*len+1;i<=r;++i) {
    35             s[b[i]].erase(a[i]);
    36             a[i]+=c;
    37             s[b[i]].insert(a[i]);
    38         }
    39     for(R i=b[l]+1;i<=b[r]-1;++i) ad[i]+=c;
    40 }
    41 
    42 IL void query(int l,int r,int x) {
    43     int ans=-1;
    44     for(R i=l;i<=min(r,b[l]*len);++i) 
    45         if(a[i]+ad[b[i]]<x) ans=max(ans,a[i]+ad[b[i]]);
    46     if(b[l]!=b[r]) 
    47         for(R i=(b[r]-1)*len+1;i<=r;++i) 
    48             if(a[i]+ad[b[i]]<x) ans=max(ans,a[i]+ad[b[i]]);
    49     for(R i=b[l]+1;i<=b[r]-1;++i) {
    50         set<int>::iterator it=s[i].lower_bound(x-ad[i]);
    51         if(it==s[i].begin()) continue;
    52         --it;ans=max(ans,*it+ad[i]);
    53     }
    54     printf("%d
    ",ans);
    55 }
    56 
    57 int main() {
    58     n=read();
    59     for(R i=1;i<=n;++i) a[i]=read();
    60     pre();
    61     for(R i=1;i<=n;++i) {
    62         int op=read(),l=read(),r=read(),c=read();
    63         if(!op) add(l,r,c);
    64         else query(l,r,c);
    65     }
    66     return 0;    
    67 }
    分块3

     

    区间加法,区间求和

     1 #include<bits/stdc++.h>
     2 #define int long long
     3 #define IL inline
     4 #define R register int
     5 #define ls(x) a[x].ch[0]
     6 #define rs(x) a[x].ch[1]
     7 #define fa(x) a[x].fa
     8 
     9 using namespace std;
    10 const int N=1e5+5,inf=0x3f3f3f3f;
    11 
    12 IL int read() {
    13     int f=1;char ch;
    14     while((ch=getchar())<'0'||ch>'9') if(ch=='-') f=-1;
    15     int res=ch-'0';
    16     while((ch=getchar())>='0'&&ch<='9') res=res*10+ch-'0';    
    17     return res*f;
    18 }
    19 
    20 int n,a[N],ad[N],b[N],len,sum[N];
    21 
    22 IL void pre() {
    23     len=sqrt(n);
    24     for(R i=1;i<=n;++i) b[i]=(i-1)/len+1,sum[b[i]]+=a[i];
    25 }
    26 
    27 IL void add(int l,int r,int c) {
    28     for(R i=l;i<=min(r,b[l]*len);++i) 
    29         a[i]+=c,sum[b[i]]+=c;
    30     if(b[l]!=b[r]) 
    31         for(R i=(b[r]-1)*len+1;i<=r;++i) 
    32             a[i]+=c,sum[b[i]]+=c;
    33     for(R i=b[l]+1;i<=b[r]-1;++i) ad[i]+=c;
    34 }
    35 
    36 IL void query(int l,int r,int x) {
    37     int ans=0;
    38     for(R i=l;i<=min(r,b[l]*len);++i) 
    39         ans+=a[i]+ad[b[i]];
    40     if(b[l]!=b[r]) 
    41         for(R i=(b[r]-1)*len+1;i<=r;++i) 
    42             ans+=a[i]+ad[b[i]];
    43     for(R i=b[l]+1;i<=b[r]-1;++i) {
    44         ans+=sum[i]+ad[i]*len;
    45     }
    46     printf("%lld
    ",ans%(x+1));
    47 }
    48 
    49 signed main() {
    50     n=read();
    51     for(R i=1;i<=n;++i) a[i]=read();
    52     pre();
    53     for(R i=1;i<=n;++i) {
    54         int op=read(),l=read(),r=read(),c=read();
    55         if(!op) add(l,r,c);
    56         else query(l,r,c);
    57     }
    58     return 0;    
    59 }
    分块4

     

    区间开方,区间求和

    //跳过已经不能再开方(元素值为0或1)的块

     1 #include<bits/stdc++.h>
     2 #define int long long
     3 #define IL inline
     4 #define R register int
     5 #define ls(x) a[x].ch[0]
     6 #define rs(x) a[x].ch[1]
     7 #define fa(x) a[x].fa
     8 
     9 using namespace std;
    10 const int N=1e5+5,inf=0x3f3f3f3f;
    11 
    12 IL int read() {
    13     int f=1;char ch;
    14     while((ch=getchar())<'0'||ch>'9') if(ch=='-') f=-1;
    15     int res=ch-'0';
    16     while((ch=getchar())>='0'&&ch<='9') res=res*10+ch-'0';    
    17     return res*f;
    18 }
    19 
    20 int n,a[N],b[N],len,sum[N],flag[N];
    21 
    22 IL void pre() {
    23     len=sqrt(n);
    24     for(R i=1;i<=n;++i) b[i]=(i-1)/len+1,sum[b[i]]+=a[i];
    25 }
    26 
    27 IL void allsqrt(int x) {
    28     if(flag[x]) return ;
    29     flag[x]=1;
    30     sum[x]=0;
    31     for(R i=(x-1)*len+1;i<=x*len;++i) {
    32         a[i]=sqrt(a[i]);sum[x]+=a[i];
    33         if(a[i]>1) flag[x]=0;
    34     }
    35 }
    36 
    37 IL void work(int l,int r,int c) {
    38     for(R i=l;i<=min(r,b[l]*len);++i) 
    39         sum[b[i]]-=a[i],a[i]=sqrt(a[i]),sum[b[i]]+=a[i];
    40     if(b[l]!=b[r]) 
    41         for(R i=(b[r]-1)*len+1;i<=r;++i) 
    42             sum[b[i]]-=a[i],a[i]=sqrt(a[i]),sum[b[i]]+=a[i];
    43     for(R i=b[l]+1;i<=b[r]-1;++i) allsqrt(i);
    44 }
    45 
    46 IL void query(int l,int r,int x) {
    47     int ans=0;
    48     for(R i=l;i<=min(r,b[l]*len);++i) 
    49         ans+=a[i];
    50     if(b[l]!=b[r]) 
    51         for(R i=(b[r]-1)*len+1;i<=r;++i) 
    52             ans+=a[i];
    53     for(R i=b[l]+1;i<=b[r]-1;++i) {
    54         ans+=sum[i];
    55     }
    56     printf("%lld
    ",ans);
    57 }
    58 
    59 signed main() {
    60     n=read();
    61     for(R i=1;i<=n;++i) a[i]=read();
    62     pre();
    63     for(R i=1;i<=n;++i) {
    64         int op=read(),l=read(),r=read(),c=read();
    65         if(!op) work(l,r,c);
    66         else query(l,r,c);
    67     }
    68     return 0;    
    69 }
    分块5

    应用:洛谷P4145 上帝造题的七分钟2 / 花神游历各国

    #include<bits/stdc++.h>
    #define int long long
    #define IL inline
    #define R register int
    #define ls(x) a[x].ch[0]
    #define rs(x) a[x].ch[1]
    #define fa(x) a[x].fa
    
    using namespace std;
    const int N=1e5+5,inf=0x3f3f3f3f;
    
    IL int read() {
        int f=1;char ch;
        while((ch=getchar())<'0'||ch>'9') if(ch=='-') f=-1;
        int res=ch-'0';
        while((ch=getchar())>='0'&&ch<='9') res=res*10+ch-'0';    
        return res*f;
    }
    
    int n,a[N],b[N],len,sum[N],flag[N];
    
    IL void pre() {
        len=sqrt(n);
        for(R i=1;i<=n;++i) b[i]=(i-1)/len+1,sum[b[i]]+=a[i];
    }
    
    IL void allsqrt(int x) {
        if(flag[x]) return ;
        flag[x]=1;
        sum[x]=0;
        for(R i=(x-1)*len+1;i<=x*len;++i) {
            a[i]=sqrt(a[i]);sum[x]+=a[i];
            if(a[i]>1) flag[x]=0;
        }
    }
    
    IL void work(int l,int r) {
        for(R i=l;i<=min(r,b[l]*len);++i) 
            sum[b[i]]-=a[i],a[i]=sqrt(a[i]),sum[b[i]]+=a[i];
        if(b[l]!=b[r]) 
            for(R i=(b[r]-1)*len+1;i<=r;++i) 
                sum[b[i]]-=a[i],a[i]=sqrt(a[i]),sum[b[i]]+=a[i];
        for(R i=b[l]+1;i<=b[r]-1;++i) allsqrt(i);
    }
    
    IL void query(int l,int r) {
        int ans=0;
        for(R i=l;i<=min(r,b[l]*len);++i) 
            ans+=a[i];
        if(b[l]!=b[r]) 
            for(R i=(b[r]-1)*len+1;i<=r;++i) 
                ans+=a[i];
        for(R i=b[l]+1;i<=b[r]-1;++i) {
            ans+=sum[i];
        }
        printf("%lld
    ",ans);
    }
    
    signed main() {
        n=read();
        for(R i=1;i<=n;++i) a[i]=read();
        int m=read();
        pre();
        for(R i=1;i<=m;++i) {
            int op=read(),l=read(),r=read();
            if(l>r) swap(l,r);
            if(!op) work(l,r);
        else query(l,r);
        }
        return 0;    
    }
    P4145代码

     

    单点插入,单点询问

    //vector自带insert、重新分块(重构)

    #include<bits/stdc++.h>
    #define int long long
    #define IL inline
    #define R register int
    #define PII pair<int,int>
    #define fi first
    #define se second
    #define mk make_pair
    
    using namespace std;
    const int N=5e5+5,inf=0x3f3f3f3f;
    
    IL int read() {
        int f=1;char ch;
        while((ch=getchar())<'0'||ch>'9') if(ch=='-') f=-1;
        int res=ch-'0';
        while((ch=getchar())>='0'&&ch<='9') res=res*10+ch-'0';    
        return res*f;
    }
    
    int n,a[N],len,st[N],m,b[N];
    vector<int> s[N];
    
    IL void pre() {
        len=sqrt(n);m=n;
        for(R i=1;i<=n;++i) b[i]=(i-1)/len+1,s[b[i]].push_back(a[i]);
    }
    
    IL PII find(int x) {
        int i=1;
        while(x>s[i].size()) x-=s[i].size(),i++;//x belongs to s[i]
        return mk(i,x-1);
    }
    
    IL void rebuild() {
        int top=0;
        for(R i=1;i<=b[m];++i) {
            for(R j=0;j<s[i].size();++j) st[++top]=s[i][j];
            s[i].clear();
        }
        len=sqrt(n);
        for(R i=1;i<=n;++i) b[i]=(i-1)/len+1,s[b[i]].push_back(st[i]);
    }
    
    IL void insert(int l,int r) {
        PII t=find(l);
        s[t.fi].insert(s[t.fi].begin()+t.se,r);
        if(s[t.fi].size()>20*len) rebuild();
    }
    
    IL void query(int r) {
        PII t=find(r);
        printf("%lld
    ",s[t.fi][t.se]);
    }
    
    signed main() {
        m=n=read();
        for(R i=1;i<=n;++i) a[i]=read();
        pre();
        for(R i=1;i<=m;++i) {
            int op=read(),l=read(),r=read(),c=read();
            if(!op) insert(l,r),++n;
            else query(r);
        }
        return 0;
    }
    分块6

     

    区间乘法,区间加法,单点询问

    //先乘后加

    #include<bits/stdc++.h>
    #define int long long
    #define IL inline
    #define R register int
    
    using namespace std;
    const int N=1e5+5,inf=0x3f3f3f3f,mod=10007;
    
    IL int read() {
        int f=1;
        char ch;
        while((ch=getchar())<'0'||ch>'9') if(ch=='-') f=-1;
        int res=ch-'0';
        while((ch=getchar())>='0'&&ch<='9') res=res*10+ch-'0';
        return res*f;
    }
    
    int n,a[N],b[N],len,ad[N],mul[N];
    
    IL void pre() {
        len=sqrt(n);
        for(R i=1; i<=n; ++i) b[i]=(i-1)/len+1,mul[b[i]]=1;
    }
    
    void reset(int x) {
        for(R i=(x-1)*len+1; i<=min(n,x*len); ++i)
            a[i]=a[i]*mul[x]%mod,a[i]=(a[i]+ad[x])%mod;
        mul[x]=1;ad[x]=0;
    }
    
    IL void work(int op,int l,int r,int c) {
        reset(b[l]);
        for(R i=l; i<=min(r,b[l]*len); ++i)
            if(op) a[i]=a[i]*c%mod;
            else a[i]=(a[i]+c)%mod;
        if(b[l]!=b[r]) {
            reset(b[r]);
            for(R i=(b[r]-1)*len+1; i<=r; ++i)
                if(op) a[i]=a[i]*c%mod;
                else a[i]=(a[i]+c)%mod;
        }
        for(R i=b[l]+1; i<=b[r]-1; ++i)
            if(op) mul[i]=mul[i]*c%mod,ad[i]=ad[i]*c%mod;
            else ad[i]=(ad[i]+c)%mod;
    }
    
    IL void query(int i) {
        int x=b[i];
        //a[i]=a[i]*mul[x]%mod,a[i]=(a[i]+ad[x])%mod;
        printf("%lld
    ",(a[i]*mul[x]%mod+ad[x])%mod);
    }
    
    signed main() {
        n=read();
        for(R i=1; i<=n; ++i) a[i]=read();
        pre();
        for(R i=1; i<=n; ++i) {
            int op=read(),l=read(),r=read(),c=read();
            if(op==2) query(r);
            else work(op,l,r,c);
        }
        return 0;
    }
    分块7

    应用:P3373 【模板】线段树 2

    //线段树模板也可以用分块来做~吸个氧还是能卡过去的

    #include<bits/stdc++.h>
    #define int long long
    #define IL inline
    #define R register int
    
    using namespace std;
    const int N=1e5+5,inf=0x3f3f3f3f;
    
    IL int read() {
        int f=1;
        char ch;
        while((ch=getchar())<'0'||ch>'9') if(ch=='-') f=-1;
        int res=ch-'0';
        while((ch=getchar())>='0'&&ch<='9') res=res*10+ch-'0';
        return res*f;
    }
    
    int n,a[N],b[N],len,ad[N],mul[N],m,p,sum[N];
    
    IL int mod(int x) {return x>p?x-p:x;}
    
    IL void pre() {
        len=sqrt(n);
        for(R i=1; i<=n; ++i) b[i]=(i-1)/len+1,mul[b[i]]=1,sum[b[i]]+=a[i];
    }
    
    void reset(int x) {
        sum[x]=0;
        for(R i=(x-1)*len+1; i<=min(n,x*len); ++i)
            a[i]=(a[i]*mul[x]+ad[x])%p,sum[x]=mod(sum[x]+a[i]);
        mul[x]=1;ad[x]=0;
    }
    
    IL void work(int op,int l,int r,int c) {
        reset(b[l]);
        for(R i=l; i<=min(r,b[l]*len); ++i)
            if(op==1) sum[b[l]]+=(c-1)*a[i]%p,a[i]=a[i]*c%p;
            else sum[b[l]]=mod(sum[b[l]]+c),a[i]=mod(a[i]+c);
        if(b[l]!=b[r]) {
            reset(b[r]);
            for(R i=(b[r]-1)*len+1; i<=r; ++i)
                if(op==1) sum[b[r]]+=(c-1)*a[i]%p,a[i]=a[i]*c%p;
                else sum[b[r]]=mod(sum[b[r]]+c),a[i]=mod(a[i]+c);
        }
        for(R i=b[l]+1; i<=b[r]-1; ++i)
            if(op==1) mul[i]=mul[i]*c%p,ad[i]=ad[i]*c%p;
            else ad[i]=mod(ad[i]+c);
    }
    
    IL void query(int l,int r) {
        int ans=0;
        reset(b[l]);
        for(R i=l; i<=min(r,b[l]*len); ++i) ans=mod(ans+a[i]);
        if(b[l]!=b[r]) {
            reset(b[r]);
            for(R i=(b[r]-1)*len+1; i<=r; ++i) ans=mod(ans+a[i]);
        }
        for(R i=b[l]+1;i<=b[r]-1;++i) ans=mod(ans+mod(sum[i]*mul[i]%p+ad[i]*len%p));
        printf("%lld
    ",ans);
    }
    
    signed main() {
        n=read(),m=read(),p=read();
        for(R i=1; i<=n; ++i) a[i]=read();
        pre();
        for(R i=1; i<=m; ++i) {
            int op=read(),l=read(),r=read();
            if(op==3) query(l,r);
            else {
                int c=read();
                work(op,l,r,c);
            }
        }
        return 0;
    }
    P3373代码

     

    区间询问等于一个数c的元素,并将这个区间的所有元素改为c

    #include<bits/stdc++.h>
    #define int long long
    #define IL inline
    #define R register int
    
    using namespace std;
    const int N=1e5+5,inf=0x3f3f3f3f;
    
    IL int read() {
        int f=1;
        char ch;
        while((ch=getchar())<'0'||ch>'9') if(ch=='-') f=-1;
        int res=ch-'0';
        while((ch=getchar())>='0'&&ch<='9') res=res*10+ch-'0';
        return res*f;
    }
    
    int n,a[N],b[N],len,tag[N];
    
    IL void pre() {
        len=sqrt(n);
        for(R i=1; i<=n; ++i) b[i]=(i-1)/len+1,tag[i]=-1;;
    }
    
    void reset(int x) {
        if(tag[x]==-1) return ;
        for(R i=(x-1)*len+1;i<=x*len;++i) a[i]=tag[x];
        tag[x]=-1;
    }
    
    IL void query(int l,int r,int c) {
        int ans=0;
        reset(b[l]);
        for(R i=l; i<=min(r,b[l]*len); ++i) 
            if(a[i]!=c) a[i]=c;
            else ans++;
        if(b[l]!=b[r]) {
            reset(b[r]);
            for(R i=(b[r]-1)*len+1; i<=r; ++i) 
                if(a[i]!=c) a[i]=c;
                else ans++;
        }
        for(R i=b[l]+1;i<=b[r]-1;++i) 
            if(tag[i]==-1) {
                for(R j=(i-1)*len+1;j<=i*len;++j) 
                    if(a[j]!=c) a[j]=c;
                    else ans++;
                tag[i]=c;
            }
            else {
                if(tag[i]==c) ans+=len;
                else tag[i]=c;
            }
        printf("%lld
    ",ans);
    }
    
    signed main() {
        n=read();
        for(R i=1; i<=n; ++i) a[i]=read();
        pre();
        for(R i=1; i<=n; ++i) {
            int l=read(),r=read(),c=read();
            query(l,r,c);
        }
        return 0;
    }
    分块8

     

    询问区间的最小众数

    预处理保存以“段边界”为端点的区间[L,R]的众数。另外,对每个数值建立一个STL vector,按顺序保存该数值在序列a中每次出现的位置。

    对于每个询问,扫描[l,L)与(R,r]中的每个数x,在对应的vector里二分查找即可得到x在[l,r]中出现的次数,从而更新答案。

    ——《算法竞赛进阶指南》

    #include<bits/stdc++.h>
    #define int long long
    #define IL inline
    #define R register int
    
    using namespace std;
    const int N=1e5+5,inf=0x3f3f3f3f;
    
    IL int read() {
        int f=1;
        char ch;
        while((ch=getchar())<'0'||ch>'9') if(ch=='-') f=-1;
        int res=ch-'0';
        while((ch=getchar())>='0'&&ch<='9') res=res*10+ch-'0';
        return res*f;
    }
    
    int n,a[N],b[N],len,f[1505][1505],cnt[N],val[N],num;
    map<int,int> m;
    vector<int> pos[N];
    
    IL void pre(int x) {
        int mx=0,ans=0;
        memset(cnt,0,sizeof(cnt));
        for(R i=(x-1)*len+1; i<=n; ++i) {
            cnt[a[i]]++;
            if(cnt[a[i]]>mx||(cnt[a[i]]==mx&&val[a[i]]<val[ans])) mx=cnt[a[i]],ans=a[i];
            f[x][b[i]]=ans;//分块间的最小众数
        }
    }
    
    IL int find(int l,int r,int x) {
        return upper_bound(pos[x].begin(),pos[x].end(),r)-lower_bound(pos[x].begin(),pos[x].end(),l);
    }
    
    IL void query(int l,int r) {
        int ans=f[b[l]+1][b[r]-1];
        int mx=find(l,r,ans);
        for(R i=l; i<=min(r,b[l]*len); ++i) {
            int tmp=find(l,r,a[i]);
            if(tmp>mx||(tmp==mx&&val[a[i]]<val[ans])) mx=tmp,ans=a[i];
        }
        if(b[l]!=b[r])
            for(R i=(b[r]-1)*len+1; i<=r; ++i) {
                int tmp=find(l,r,a[i]);
                if(tmp>mx||(tmp==mx&&val[a[i]]<val[ans])) mx=tmp,ans=a[i];
            }
        printf("%lld
    ",val[ans]);
    }
    
    signed main() {
        n=read();
        for(R i=1; i<=n; ++i) {
            a[i]=read();
            if(!m[a[i]]) {
                m[a[i]]=++num;
                val[num]=a[i];
            }
            a[i]=m[a[i]];
            pos[a[i]].push_back(i);
        }
        len=80;
        for(R i=1; i<=n; ++i) b[i]=(i-1)/len+1;
        for(R i=1; i<=b[n]; ++i) pre(i);
        for(R i=1; i<=n; ++i) {
            int l=read(),r=read();
            if(l>r) swap(l,r);
            query(l,r);
        }
        return 0;
    }
    分块9

    应用:洛谷P4168 [Violet]蒲公英

    #include<bits/stdc++.h>
    #define int long long
    #define IL inline
    #define R register int
    
    using namespace std;
    const int N=1e5+5,inf=0x3f3f3f3f;
    
    IL int read() {
        int f=1;
        char ch;
        while((ch=getchar())<'0'||ch>'9') if(ch=='-') f=-1;
        int res=ch-'0';
        while((ch=getchar())>='0'&&ch<='9') res=res*10+ch-'0';
        return res*f;
    }
    
    int n,a[N],b[N],len,f[1505][1505],cnt[N],val[N],num,lastans;
    map<int,int> m;
    vector<int> pos[N];
    
    IL void pre(int x) {
        int mx=0,ans=0;
        memset(cnt,0,sizeof(cnt));
        for(R i=(x-1)*len+1; i<=n; ++i) {
            cnt[a[i]]++;
            if(cnt[a[i]]>mx||(cnt[a[i]]==mx&&val[a[i]]<val[ans])) mx=cnt[a[i]],ans=a[i];
            f[x][b[i]]=ans;//分块间的最小众数
        }
    }
    
    IL int find(int l,int r,int x) {
        return upper_bound(pos[x].begin(),pos[x].end(),r)-lower_bound(pos[x].begin(),pos[x].end(),l);
    }
    
    IL int query(int l,int r) {
        int ans=f[b[l]+1][b[r]-1];
        int mx=find(l,r,ans);
        for(R i=l; i<=min(r,b[l]*len); ++i) {
            int tmp=find(l,r,a[i]);
            if(tmp>mx||(tmp==mx&&val[a[i]]<val[ans])) mx=tmp,ans=a[i];
        }
        if(b[l]!=b[r])
            for(R i=(b[r]-1)*len+1; i<=r; ++i) {
                int tmp=find(l,r,a[i]);
                if(tmp>mx||(tmp==mx&&val[a[i]]<val[ans])) mx=tmp,ans=a[i];
            }
        return val[ans];
    }
    
    signed main() {
        n=read();int M=read();
        for(R i=1; i<=n; ++i) {
            a[i]=read();
            if(!m[a[i]]) {
                m[a[i]]=++num;
                val[num]=a[i];
            }
            a[i]=m[a[i]];
            pos[a[i]].push_back(i);
        }
        len=80;
        for(R i=1; i<=n; ++i) b[i]=(i-1)/len+1;
        for(R i=1; i<=b[n]; ++i) pre(i);
        for(R i=1; i<=M; ++i) {
            int l=read(),r=read();
            l=(l+lastans-1)%n+1,r=(r+lastans-1)%n+1;
            if(l>r) swap(l,r);
            lastans=query(l,r);
            printf("%lld
    ",lastans);
        }
        return 0;
    }
    P4168代码

    洛谷P4135 作诗

    和询问区间众数差不多。预处理出分块间正偶数的个数,查询时根据奇偶性具体判断即可。(在洛谷不开O(2)也能过

    #include<bits/stdc++.h>
    #define int long long
    #define IL inline
    #define R register int
    
    using namespace std;
    const int N=1e5+5,inf=0x3f3f3f3f;
    
    IL int read() {
        int f=1;
        char ch;
        while((ch=getchar())<'0'||ch>'9') if(ch=='-') f=-1;
        int res=ch-'0';
        while((ch=getchar())>='0'&&ch<='9') res=res*10+ch-'0';
        return res*f;
    }
    
    int n,m,c,a[N],b[N],len,f[1505][1505],cnt[N],val[N],num,lastans,vis[N];
    
    vector<int> pos[N];
    
    IL void pre(int x) {
        int tot=0;
        for(R i=(x-1)*len+1; i<=n; ++i) cnt[a[i]]=0;
        for(R i=(x-1)*len+1; i<=n; ++i) {
            if(cnt[a[i]]!=0&&cnt[a[i]]%2==0) tot--;
            cnt[a[i]]++;
            if(cnt[a[i]]%2==0) tot++;
            f[x][b[i]]=tot;
        }
    }
    
    IL int find(int l,int r,int x) {
        return upper_bound(pos[x].begin(),pos[x].end(),r)-lower_bound(pos[x].begin(),pos[x].end(),l);
    }
    
    IL int query(int l,int r) {
        int ans;
        if(b[l]==b[r]||b[l]+1==b[r]) {
            ans=0;
            
            for(R i=l; i<=r; ++i) {
                if(vis[a[i]]) continue;
                vis[a[i]]=1;
                int tmp=find(l,r,a[i]);
                if(tmp%2==0) ans++;
            }
            for(R i=l; i<=r; ++i)    vis[a[i]]=0;
        }
        else{
            ans=f[b[l]+1][b[r]-1];//b[l]+1~b[r]-1中的正偶数个数
            int x=b[l]*len+1,y=(b[r]-1)*len;
            
            for(R i=l; i<x; ++i) {
                if(vis[a[i]]) continue;
                vis[a[i]]=1;
                int tmp=find(l,r,a[i]),bef=find(x,y,a[i]);
                if(tmp%2==0) {
                    if(bef%2==1||bef==0) ans++;
                } else if(bef&&(bef%2==0)) ans--;
            }
            
            for(R i=y+1; i<=r; ++i) {
                if(vis[a[i]]) continue;
                vis[a[i]]=1;
                int tmp=find(l,r,a[i]),bef=find(x,y,a[i]);
                if(tmp%2==0) {
                    if(bef%2==1||bef==0) ans++;
                } else if(bef&&(bef%2==0)) ans--;
            }
            for(R i=l; i<x; ++i) vis[a[i]]=0;
            for(R i=y+1; i<=r; ++i) vis[a[i]]=0;
        }
        return ans;
    }
    
    signed main() {
        n=read();
        c=read();
        m=read();
        len=sqrt((double)n/log((double)n)*log(2));
        for(R i=1; i<=n; ++i) {
            a[i]=read();
            pos[a[i]].push_back(i);
            b[i]=(i-1)/len+1;
        }
        for(R i=1; i<=b[n]; ++i) pre(i);
        for(R i=1; i<=m; ++i) {
            int l=read(),r=read();
            l=(l+lastans)%n+1,r=(r+lastans)%n+1;
            if(l>r) swap(l,r);
            lastans=query(l,r);
            printf("%lld
    ",lastans);
        }
        return 0;
    }
    P4135代码
     
  • 相关阅读:
    十分钟内学会:将HTML格式化为合法的XML
    十分钟内学会:根据数据库生成站点导航
    Adobe Apollo vs Joyeur Slingshot
    英语阅读推荐:你真的懂UPDATE语句吗 & 当有layout之时
    欲练 CSS ,必先宫 IE
    英语阅读推荐:海明威写作技巧 & UpdatePanel为何失灵
    英语阅读推荐:在AJAX中制作自定义验证服务 & 优秀网站的5个因素
    Code is Configuration
    十分钟内学会:自动识别GB2312与UTF8编码的文件
    学习 Ruby on Rails 真的很爽!
  • 原文地址:https://www.cnblogs.com/ljy-endl/p/14527589.html
Copyright © 2011-2022 走看看