zoukankan      html  css  js  c++  java
  • BZOJ 2724: [Violet 6]蒲公英 [分块 区间众数]

    传送门

    题面太美不忍不放


    分块分块

    这种题的一个特点是只有查询,通常需要预处理;加入修改的话需要暴力重构预处理

    预处理$f[i][j]$为第i块到第j块的众数,显然$f[i][j]=max{f[i][j-1],j中出现的数}$,复杂度$O(N^2/S)$,常数比较小吧

    最近用$pair$上瘾了...

    然后查询$[l,r]$时,整块直接查,两边不完整的枚举出现的数,然后加上整块里出现次数来更新

    求整块的出现次数,可以用$v[i]$表示数字$i$出现位置,二分来找,复杂度$O(NSlogN)$

    或者clj orz的论文里还有预处理的方法,预处理$s[i][x]$前i个块x的次数和$ss[i][j][x]$第i块前j个中k出现次数,貌似代码量会很大....

    所以说这种vector+二分来找一个区间内某个数出现次数还是比较巧妙的呀....

    然后分块一定要分$sqrt{frac{N}{logN}}$大小,比根号快了1倍多.....

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <cmath>
    #include <vector>
    using namespace std;
    #define pii pair<int, int>
    #define MP make_pair
    #define fir first
    #define sec second
    const int N=4e4+5,M=800;
    typedef unsigned long long ll;
    inline int read(){
        char c=getchar();int x=0,f=1;
        while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
        while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
        return x*f;
    }
    int n,Q,x,y,a[N],mp[N];
    vector<int> v[N];
    int pos[N],m,block;
    struct _blo{int l,r;} b[M];
    inline void ini(){
        if(n==1) block=1;
        else block=sqrt(n/log2(n));
        m=(n-1)/block+1;
        for(int i=1;i<=n;i++) pos[i]=(i-1)/block+1;
        for(int i=1;i<=m;i++) b[i].l=(i-1)*block+1,b[i].r=i*block;
        b[m].r=n;
    }
    //struct I{int x; bool operator <(const I &r) const{return x>r.x;} I(int a=0):x(a){} };
    pii f[M][M];
    int c[N];
    struct Block{
        void set(int x){
            memset(c,0,sizeof(c));
            pii now(0,0);
            for(int i=b[x].l;i<=n;i++){
                c[a[i]]++; int t=pos[i];
                now=max(now,MP( c[a[i]],-a[i] ) );//-a[i]
                f[x][t]=now;
            }
        }
        int cou(int l,int r,int x){
            return upper_bound(v[x].begin(),v[x].end(),r) - lower_bound(v[x].begin(),v[x].end(),l);
        }
        int que(int l,int r){//printf("que %d %d
    ",l,r);
            pii re=f[pos[l]+1][pos[r]-1];
            if(pos[l]==pos[r])
                for(int i=l;i<=r;i++) re=max(re,MP( cou(l,r,a[i]),-a[i] ) );
            else{
                for(int i=l;i<=b[pos[l]].r;i++) re=max(re,MP( cou(l,r,a[i]),-a[i] ) );
                for(int i=b[pos[r]].l;i<=r;i++) re=max(re,MP( cou(l,r,a[i]),-a[i] ) );
            }
            return -re.sec;
        }
    }B;
    int main(){
        freopen("in","r",stdin);
        n=read();Q=read();
        for(int i=1;i<=n;i++) a[i]=mp[i]=read();
        sort(mp+1,mp+1+n); mp[0]=unique(mp+1,mp+1+n)-mp-1;
        for(int i=1;i<=n;i++) 
            a[i]=lower_bound(mp+1,mp+1+mp[0],a[i])-mp , v[a[i]].push_back(i);
        ini();
        for(int i=1;i<=m;i++) B.set(i);
        int last=0;
        while(Q--){
            int l=(read()+last-1)%n+1,r=(read()+last-1)%n+1;
            if(l>r) swap(l,r);
            last=mp[ B.que(l,r) ];
            printf("%d
    ",last);
        }
    }
    7796ms

    [2017-03-15 16:41:05]

    又想了一下,$ss$其实不用预处理,查询的时候暴力算就行了

    然后来享受没有$log$的优越,3372ms到第一页啦啦啦

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <cmath>
    using namespace std;
    #define pii pair<int, int>
    #define MP make_pair
    #define fir first
    #define sec second
    const int N=4e4+5,M=350;
    typedef unsigned long long ll;
    inline int read(){
        char c=getchar();int x=0,f=1;
        while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
        while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
        return x*f;
    }
    int n,Q,x,y,a[N],mp[N];
    int pos[N],m,block;
    struct _blo{int l,r;} b[M];
    inline void ini(){
        block=sqrt(n);
        m=(n-1)/block+1;
        for(int i=1;i<=n;i++) pos[i]=(i-1)/block+1;
        for(int i=1;i<=m;i++) b[i].l=(i-1)*block+1,b[i].r=i*block;
        b[m].r=n;
    }
    
    pii f[M][M];
    int c[N],s[M][N];
    struct Block{
        void set(int x){
            memset(c,0,sizeof(c));
            pii now(0,0);
            for(int i=b[x].l;i<=n;i++){
                c[a[i]]++; int t=pos[i];
                now=max(now,MP( c[a[i]],-a[i] ) );
                f[x][t]=now;
            }
            for(int i=1;i<=mp[0];i++) s[x][i]=s[x-1][i];
            for(int i=b[x].l;i<=b[x].r;i++) s[x][a[i]]++;
        }
    
        int t[N];
        int que(int l,int r){
            pii re=f[pos[l]+1][pos[r]-1];
            if(pos[l]==pos[r]){
                for(int i=l;i<=r;i++) t[a[i]]=0;
                for(int i=l;i<=r;i++) re=max(re,MP( ++t[a[i]],-a[i] ) );
            }else{
                int L=pos[l],R=pos[r]-1;
                for(int i=l;i<=b[pos[l]].r;i++) t[a[i]]=s[R][ a[i] ] - s[L][ a[i] ];
                for(int i=b[pos[r]].l;i<=r;i++) t[a[i]]=s[R][ a[i] ] - s[L][ a[i] ];
                for(int i=l;i<=b[pos[l]].r;i++) re=max(re,MP( ++t[a[i]],-a[i] ) );
                for(int i=b[pos[r]].l;i<=r;i++) re=max(re,MP( ++t[a[i]],-a[i] ) );
            }
            return -re.sec;
        }
    }B;
    int main(){
        freopen("in","r",stdin);
        n=read();Q=read();
        for(int i=1;i<=n;i++) a[i]=mp[i]=read();
        sort(mp+1,mp+1+n); mp[0]=unique(mp+1,mp+1+n)-mp-1;
        for(int i=1;i<=n;i++) 
            a[i]=lower_bound(mp+1,mp+1+mp[0],a[i])-mp;
    
        ini();
        for(int i=1;i<=m;i++) B.set(i);
        int last=0;
        while(Q--){
            int l=(read()+last-1)%n+1,r=(read()+last-1)%n+1;
            if(l>r) swap(l,r);
            last=mp[ B.que(l,r) ];
            printf("%d
    ",last);
        }
    }
  • 相关阅读:
    金蝶软件常用基础SQL数据表
    改变cxgrid行字体颜色
    C#默认修饰符
    const和static
    怎么写动态游标
    Report Machine支持导出PDF
    C1TrueDBGrid注册码
    免费在线思维导图工具Mindv V1.1.0发布
    支持中文输入的免费的Silverlight Richtextbox
    云计算浅谈之一:云计算介绍
  • 原文地址:https://www.cnblogs.com/candy99/p/6554633.html
Copyright © 2011-2022 走看看