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\n",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\n",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\n",last);
    }
}

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM