BZOJ---4241:历史研究【回滚莫队】

题目:

BZOJ---4241:历史研究

题意:

给出 N个数,Q 次询问区间【qL,qR】内每个数 * 出现次数 的最大值

分析:

回滚莫队的板子题

学习自:『回滚莫队及其简单运用』

普通莫队每次添加数和删除数都要及时维护答案,但有时候删除数不好维护,有时候添加数不好维护,回滚莫队能在同样的复杂度内只维护添加数或删除数 

代码: 

#include 
 
#define x first
#define y second
#define pii pair
#define sz(x) (int)(x).size()
#define Max(x,y) (x)>(y)?(x):(y)
#define Min(x,y) (x)<(y)?(x):(y)
#define all(x) (x).begin(),(x).end()
using namespace std;
typedef long long LL;
const int maxn = 1e5+56;
const int mod = 998244353;
int n,m,block,a[maxn],c[maxn],cnt,mp[maxn];
inline int getid(int x){
    return lower_bound(c,c+cnt,x) - c;
}
struct query{
    int L,R,b,id;
}q[maxn];
inline bool cmp(query a,query b){
    return a.b==b.b ? a.R < b.R : a.b < b.b;
}
LL res[maxn];
void solve(){
    int qR = 0, qL = 0; LL tep = 0;
    for(int i = 1;i <= m; ++i){
        if(!q[i].b) continue;
        if(q[i].b != q[i-1].b){
            for(int j = q[i-1].b*block+1;j <= qR; ++j) mp[a[j]]--;
            qL = block*q[i].b; qR = block*q[i].b; tep = 0;
        }
        LL ans = 0;
        while(qR < q[i].R){
            qR++;
            mp[a[qR]]++;
            tep = Max(tep,1ll*mp[a[qR]]*c[a[qR]]);
        }
        for(int j = qL;j >= q[i].L; --j){
            mp[a[j]]++;
            ans = Max(ans,1ll*mp[a[j]]*c[a[j]]);
        }
        for(int j = qL;j >= q[i].L; --j) mp[a[j]]--;
        res[q[i].id] = Max(tep,ans);
    }
}
LL cal(int L,int R){
    LL ans = 0;
    for(int i = L;i <= R; ++i){
        mp[a[i]]++;
        ans = Max(ans,1ll*mp[a[i]]*c[a[i]]);
    }
    for(int i = L;i <= R; ++i) mp[a[i]]--;
    return ans;
}
int main(){
    scanf("%d %d",&n,&m); block = sqrt(n*1.0)+1;
    for(int i = 1;i <= n; ++i){
        scanf("%d",a+i);
        c[cnt++] = a[i];
    }
    sort(c,c+cnt);cnt = unique(c,c+cnt) - c;
    for(int i = 1;i <= n; ++i) a[i] = getid(a[i]);
    for(int i = 1;i <= m; ++i){
        scanf("%d %d",&q[i].L,&q[i].R);
        q[i].b = (q[i].L-1)/block+1; q[i].id = i;
        if(q[i].b == (q[i].R-1)/block+1){
            q[i].b = 0;
            res[i] = cal(q[i].L,q[i].R);
        }
    }
    sort(q+1,q+m+1,cmp); solve();
    for(int i = 1;i <= m; ++i) printf("%lld\n",res[i]);
    return 0;
}
/*
3 2
2 2 3
1 3
2 3
*/

 

你可能感兴趣的:(数据结构----莫队/分块)