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);
    }
}

 

posted @ 2017-03-15 15:50  Candy?  阅读(1097)  评论(3编辑  收藏  举报