LOJ---6285:数列分块入门 9【区间众数】

题目:

https://loj.ac/problem/6285

分析:

如果只查询众数的个数,完全可以莫队,加数时容易维护众数的数量,删除数时,众数的数量要么减1,要么不变,只需再开一个标记数组维护众数的数量即可

根据陈立杰---《区间众数解题报告》实现了下面两种解法

解法一:

块数分成sqrt(n)超时了,150可以过(分块真毒瘤)

#pragma GCC optimize(2)
#include 

using namespace std;
const int MAXN = 1e5 + 15;
int a[MAXN], b[MAXN], c[MAXN], vis[MAXN], belong[MAXN], dp[1000][1000], block, n, m, L, R;
void cal(int x) {
    int res = 0, cnt = 0;
    memset(vis, 0, sizeof(vis));
    for (int i = (x - 1) * block + 1; i <= n; ++i) {
        vis[c[i]]++;
        if (vis[c[i]] > cnt) res = c[i], cnt = vis[c[i]];
        else if (vis[c[i]] == cnt && c[i] < res) res = c[i];
        dp[x][belong[i]] = res;
    }
}
std::vector pos[MAXN];
int Find(int x, int l, int r) {
    return upper_bound(pos[x].begin(), pos[x].end(), r) - lower_bound(pos[x].begin(), pos[x].end(), l);
}
int query(int l, int r) {
    int res = 0, cnt = 0;
    if (belong[l] == belong[r]) {
        for (int i = l; i <= r; ++i) {
            int tep = Find(c[i], l, r);
            if (tep > cnt) cnt = tep, res = c[i];
            else if (tep == cnt && c[i] < res) res = c[i];
        }
    } else {
        res = dp[belong[l] + 1][belong[r] - 1];
        cnt = Find(res, l, r);
        for (int i = l; i <= belong[l] * block; ++i) {
            int tep = Find(c[i], l, r);
            if (tep > cnt) cnt = tep, res = c[i];
            else if (tep == cnt && c[i] < res) res = c[i];
        }
        for (int i = (belong[r] - 1) * block + 1; i <= r; ++i) {
            int tep = Find(c[i], l, r);
            if (tep > cnt) cnt = tep, res = c[i];
            else if (tep == cnt && c[i] < res) res = c[i];
        }
    }
    return res;
}
inline int read() {
    int x = 0, f = 1;
    char c = getchar();
    for (; !isdigit(c); c = getchar()) if (c == '-') f = -1;
    for (; isdigit(c); c = getchar()) x = x * 10 + c - '0';
    return x * f;
}
inline void write(int x) {
    if (x >= 10) write(x / 10);
    putchar(x % 10 + '0');
}
int main() {
    n = read();
    block = 150, m = n / block + (n % block > 0);
    for (int i = 1; i <= n; ++i) a[i] = read(), b[i] = a[i];
    sort(b + 1, b + n + 1);
    int len = unique(b + 1, b + n + 1) - b;
    for (int i = 1; i <= n; ++i) {
        c[i] = lower_bound(b + 1, b + len, a[i]) - b;
        pos[c[i]].emplace_back(i);
        belong[i] = (i - 1) / block + 1;
    }
    for (int i = 1; i <= m; ++i) cal(i);
    for (int i = 1; i <= n; ++i) {
        L = read(), R = read();
        write(b[query(L, R)]);
        putchar('\n');
    }
    return 0;
}

优化后的解法二:

块数调来调去,不是TLE就是MLE,以后有数据范围小一点的再去试试

#pragma GCC optimize(2)
#include 
using namespace std;
const int MAXN = 1e5+15;
const int maxn = 320;
int a[MAXN],b[MAXN],c[MAXN],vis[MAXN],belong[MAXN],Dp[maxn][maxn],num[maxn][maxn],dp[maxn][MAXN],ID[maxn][MAXN],DP[maxn][maxn][maxn],block,n,m,L,R;
map v;
void cal(int x){
    for(int i = 1;i <= n; ++i) dp[x][i] = dp[x-1][i];
    int l = (x-1)*block+1,r = min(x*block,n),id = 0;
    v.clear();
    for(int i = l;i <= r; ++i) {
        dp[x][c[i]]++;
        if(!v[c[i]]) v[c[i]] = ++id;
        ID[x][c[i]] = v[c[i]];
        for(int j = 0;j <= id; ++j) DP[x][i-l+1][j] = DP[x][i-l][j];
        DP[x][i-l+1][v[c[i]]] ++;
    }
    int res = 0, cnt = 0;
    memset(vis, 0, sizeof(vis));
    for (int i = (x - 1) * block + 1; i <= n; ++i) {
        vis[c[i]]++;
        if (vis[c[i]] > cnt) res = c[i], cnt = vis[c[i]];
        else if (vis[c[i]] == cnt && c[i] < res) res = c[i];
        Dp[x][belong[i]] = res;
        num[x][belong[i]] = cnt;
    }
}
int query(int l,int r){
    int res = 0,cnt = 0;
    if(belong[l] == belong[r]){
        int x = belong[l],xL = (x-1)*block+1;
        for(int i = l;i <= r; ++i){
            int tep = DP[x][r-xL+1][ID[x][c[i]]] - DP[x][l-xL][ID[x][c[i]]];
            if(tep > cnt || (tep==cnt&&c[i] cnt || (tep==cnt&&c[i] cnt || (tep==cnt&&c[i]= 10) write(x / 10);
    putchar(x % 10 + '0');
}
int main(){
    n = read();
    block = sqrt(n*1.0),m = n/block + (n%block > 0);
    for(int i = 1;i <= n; ++i) a[i] = read(),b[i] = a[i];
    sort(b+1,b+n+1);
    int len = unique(b+1,b+n+1) - b;
    for(int i = 1;i <= n; ++i){
        c[i] = lower_bound(b+1,b+len,a[i]) - b;
        belong[i] = (i-1)/block + 1;
    }
    for(int i = 1;i <= m; ++i) cal(i);
    for(int i = 1;i <= n; ++i){
        L = read(),R = read();
        write(b[query(L,R)]);
        putchar('\n');
    }
    return 0;
}

 

 

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