蒲 公 英

原题链接
在线求区间众数.
众数不满足“区间可加性”, 考虑分块
设将长度为 N N N 的序列分成 T T T 块, 有 M M M 个询问.
对于每个询问 [ l , r ] [l, r] [l,r], 设 l l l 处于第 p p p 块, 设 r r r 处于第 q q q 块, 区间 [ l , r ] [l, r] [l,r] 分成 [ l , L ) , [ L , R ] , ( R , r ] [l, L), [L, R], (R, r] [l,L),[L,R],(R,r] 三部分, 其中 [ L , R ] [L, R] [L,R] 即为整个第 p + 1 p+1 p+1~ q − 1 q-1 q1 块.
答案仅可能来自 [ L , R ] [L, R] [L,R] 的众数或出现在 [ l , L ) [l, L) [l,L) ( R , r ] (R, r] (R,r] 之间的数.

法一

  • 预处理 c n t L , R cnt_{L, R} cntL,R 表示区间 [ L , R ] [L, R] [L,R] 中每个数出现的次数,并得出区间 [ L , R ] [L, R] [L,R] 内的众数,其中 L L L 是某一个块的左端点, R R R 是某一个块的右端点,这部分时间复杂度和空间复杂度均为 O ( N T 2 ) O(NT^2) O(NT2).

  • 对于每个询问的 [ l , L ) [l, L) [l,L) ( R , r ] (R, r] (R,r], 在数组 c n t L , R cnt_{L, R} cntL,R 的基础上累加次数, 得到答案并把数组复原.

  • 时间复杂度 O ( N T 2 + M N / T ) , T = M 3 O(NT^2 +MN/T), T=\sqrt[3]{M} O(NT2+MN/T),T=3M 时时间复杂度最优, 为 O ( N M 2 3 ) O(NM^\frac{2}{3}) O(NM32). N , M N, M N,M 同阶时 T = N 3 T=\sqrt[3]{N} T=3N , 时间复杂度 O ( N 5 3 ) O(N^\frac{5}{3}) O(N35).

法二

  • 预处理区间 [ L , R ] [L, R] [L,R] 的众数,其中 L L L 是某一个块的左端点, R R R 是某一个块的右端点.
  • 对每个数值建 v e c t o r vector vector, 保存该数值的出现位置.
  • 二分查找每个可能答案在询问区间的出现次数.
  • 时间复杂度 O ( N T + M N / T log ⁡ N ) , T = M log ⁡ N O(NT+MN/T\log{N}),T=\sqrt{M\log{N}} O(NT+MN/TlogN),T=MlogN 时时间复杂度最优,为 O ( N M log ⁡ N ) O(N\sqrt{M\log{N}}) O(NMlogN ), N , M N, M N,M 同阶时 T = N log ⁡ N T=\sqrt{N\log{N}} T=NlogN , 时间复杂度 O ( N N log ⁡ N ) O(N\sqrt{N\log{N}}) O(NNlogN ).

法三

  • 预处理每个块的众数.
  • 对每个数值建 v e c t o r vector vector, 保存该数值的出现位置.
  • 二分查找每个可能答案在询问区间的出现次数.
  • 时间复杂度 O ( N + M ( N / T + T ) log ⁡ N ) , T = N O(N+M(N/T+T)\log{N}),T=\sqrt{N} O(N+M(N/T+T)logN),T=N 时时间复杂度最优,为 O ( N + M N log ⁡ N ) O(N+M\sqrt{N}\log{N}) O(N+MN logN), N , M N, M N,M 同阶时时间复杂度 O ( N N log ⁡ N ) O(N\sqrt{N}\log{N}) O(NN logN).

代码如下:

法一:

#include <bits/stdc++.h>

using namespace std;

inline int read() {
    int x = 0, f = 0; char ch = getchar();
    while (!isdigit(ch)) f = ch == '-', ch = getchar();
    while (isdigit(ch)) x = (x << 3) + (x << 1) + (ch ^ 48), ch = getchar();
    return f ? -x : x;
}

const int N = 40010, T = 40; 
int n, m, a[N], tmp[N], cnt[T][T][N], ans[T][T]; 
int l[N], r[N], pos[N], block; 

int Query(int x, int y) {
    int p = pos[x], q = pos[y], res = 0; 
    if (p == q) {
        for (int i = x; i <= y; ++i) {
            ++cnt[0][0][a[i]]; 
            if (cnt[0][0][a[i]] > cnt[0][0][res] || (cnt[0][0][a[i]] == cnt[0][0][res] && a[i] < res)) res = a[i]; 
        }
        for (int i = x; i <= y; ++i) {
            --cnt[0][0][a[i]]; 
        }
        return res; 
    }
    res = ans[p + 1][q - 1]; 
    for (int i = x; i <= r[p]; ++i) {
        ++cnt[p + 1][q - 1][a[i]]; 
        if (cnt[p + 1][q - 1][a[i]] > cnt[p + 1][q - 1][res] || (cnt[p + 1][q - 1][a[i]] == cnt[p + 1][q - 1][res] && a[i] < res)) res = a[i]; 
    }
    for (int i = l[q]; i <= y; ++i) {
        ++cnt[p + 1][q - 1][a[i]]; 
        if (cnt[p + 1][q - 1][a[i]] > cnt[p + 1][q - 1][res] || (cnt[p + 1][q - 1][a[i]] == cnt[p + 1][q - 1][res] && a[i] < res)) res = a[i]; 
    }
    for (int i = x; i <= r[p]; ++i) {
        --cnt[p + 1][q - 1][a[i]]; 
    }
    for (int i = l[q]; i <= y; ++i) {
        --cnt[p + 1][q - 1][a[i]]; 
    }
    return res; 
}

int main() {
    n = read(); m = read(); 
    block = cbrt(n); 
    for (int i = 1; i <= block; ++i) {
        l[i] = (i - 1) * (n / block) + 1; 
        r[i] = i * (n / block); 
    }
    if (r[block] < n) ++block, l[block] = r[block - 1] + 1, r[block] = n; 
    for (int i = 1; i <= n; ++i) a[i] = tmp[i] = read(); 
    sort(tmp + 1, tmp + n + 1); 
    int len = unique(tmp + 1, tmp + n + 1) - (tmp + 1); 
    for (int i = 1; i <= n; ++i) {
        a[i] = lower_bound(tmp + 1, tmp + len + 1, a[i]) - tmp; 
    }
    for (int i = 1; i <= block; ++i) {
        for (int j = l[i]; j <= r[i]; ++j) {
            pos[j] = i;  
        }
    }
    for (int i = 1; i <= block; ++i) {
        for (int j = i; j <= block; ++j) {
            for (int k = l[i]; k <= r[j]; ++k) {
                ++cnt[i][j][a[k]]; 
                if (cnt[i][j][a[k]] > cnt[i][j][ans[i][j]] || (cnt[i][j][a[k]] == cnt[i][j][ans[i][j]] && a[k] < ans[i][j])) ans[i][j] = a[k]; 
            }
        }
    }
    int la = 0; 
    while (m--) {
        int x = ((read() + la - 1) % n) + 1, y = ((read() + la - 1) % n) + 1; 
        if (x > y) swap(x, y); 
        printf("%d\n", la = tmp[Query(x, y)]); 
    } 
    return 0;
}

法二:

#include <bits/stdc++.h>

using namespace std;

inline int read() {
    int x = 0, f = 0; char ch = getchar();
    while (!isdigit(ch)) f = ch == '-', ch = getchar();
    while (isdigit(ch)) x = (x << 3) + (x << 1) + (ch ^ 48), ch = getchar();
    return f ? -x : x;
}

const int N = 40010, T = 3710; 
int n, m, a[N], tmp[N];
int block, l[N], r[N], pos[N]; 
int cnt[N], ans[T][T]; 
vector<int> vis[N]; 

int Query(int x, int y) {
    int p = pos[x], q = pos[y], res = 0, pp = 0; 
    if (p == q) {
        for (int i = x; i <= y; ++i) {
            int left = lower_bound(vis[a[i]].begin(), vis[a[i]].end(), x) - vis[a[i]].begin(),
                right = upper_bound(vis[a[i]].begin(), vis[a[i]].end(), y) - vis[a[i]].begin() - 1;
            int len = right - left + 1; 
            if (len > pp || (len == pp && a[i] < res)) res = a[i], pp = len; 
        }
        return res; 
    }
    for (int i = x; i <= r[p]; ++i) {
        int left = lower_bound(vis[a[i]].begin(), vis[a[i]].end(), x) - vis[a[i]].begin(),
            right = upper_bound(vis[a[i]].begin(), vis[a[i]].end(), y) - vis[a[i]].begin() - 1;
        int len = right - left + 1; 
        if (len > pp || (len == pp && a[i] < res)) res = a[i], pp = len; 
    }
    for (int i = l[q]; i <= y; ++i) {
        int left = lower_bound(vis[a[i]].begin(), vis[a[i]].end(), x) - vis[a[i]].begin(),
            right = upper_bound(vis[a[i]].begin(), vis[a[i]].end(), y) - vis[a[i]].begin() - 1;
        int len = right - left + 1; 
        if (len > pp || (len == pp && a[i] < res)) res = a[i], pp = len; 
    }
    if (q - p >= 2) {
        int left = lower_bound(vis[ans[p + 1][q - 1]].begin(), vis[ans[p + 1][q - 1]].end(), x) - vis[ans[p + 1][q - 1]].begin(), 
            right = upper_bound(vis[ans[p + 1][q - 1]].begin(), vis[ans[p + 1][q - 1]].end(), y) - vis[ans[p + 1][q - 1]].begin() - 1; 
        int len = right - left + 1; 
        if (len > pp || (len == pp && ans[p + 1][q - 1] < res)) res = ans[p + 1][q - 1], pp = len; 
    }
    return res; 
}

int main() {
    n = read(); m = read(); 
    block = sqrt(m * ceil(log2(n))); 
    for (int i = 1; i <= block; ++i) {
        l[i] = (i - 1) * (n / block) + 1; 
        r[i] = i * (n / block); 
    }
    int lenn = (n / block); 
    while (r[block] < n) ++block, l[block] = r[block - 1] + 1, r[block] = min(n, block * lenn); 
    for (int i = 1; i <= block; ++i) {
        for (int j = l[i]; j <= r[i]; ++j) {
            pos[j] = i; 
        }
    }
    for (int i = 1; i <= n; ++i) tmp[i] = a[i] = read();
    sort(tmp + 1, tmp + n + 1); 
    int len = unique(tmp + 1, tmp + n + 1) - (tmp + 1); 
    for (int i = 1; i <= n; ++i) {
        a[i] = lower_bound(tmp + 1, tmp + len + 1, a[i]) - tmp;  
        vis[a[i]].push_back(i); 
    }
    for (int i = 1; i <= block; ++i) {
        memset(cnt, 0, sizeof cnt); 
        for (int j = i; j <= block; ++j) {
            ans[i][j] = ans[i][j - 1]; 
            for (int k = l[j]; k <= r[j]; ++k) {
                ++cnt[a[k]]; 
                if (cnt[a[k]] > cnt[ans[i][j]] || (cnt[a[k]] == cnt[ans[i][j]] && a[k] < ans[i][j])) ans[i][j] = a[k]; 
            }
        }
    }
    int la = 0; 
    while (m--) {
        int x = ((read() + la - 1) % n) + 1, y = ((read() + la - 1) % n) + 1; 
        if (x > y) swap(x, y); 
        printf("%d\n", la = tmp[Query(x, y)]); 
    } 
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值