P4168 [Violet]蒲公英 分块

P4168 [Violet]蒲公英

题目链接

​ 分块。

​ 一看到这数据范围肯定要离散化。而且强制在线,不可用莫队做。

\(p[i][j]\)表示第\(i\)个块到第\(j\)个块内的众数,预处理出来就好了,枚举\(i\)\(j\)\(O(\sqrt n)\)的,枚举\(j\)块内的数也是\(O(\sqrt n)\)的,总复杂度\(O(n\sqrt n)\)

\(sum[i][h]\)表示前\(i\)个块数字\(h\)出现的个数,预处理是\(O(n)\)的。

​ 对于每一个查询,假设左端点\(l\)所在的块是\(x\),右端点\(r\)所在的块是\(y\),然后分情况:

​ 如果\(y - x <= 2\),直接暴力,最多扫\(3 *\sqrt n\)个数,复杂度\(O( \sqrt n)\)

​ 如果\(y - x > 2\),我们可以确定这个众数一定出现在两边的残块中或中间的整块中,我们只需枚举残块中的每个数,用预处理出来的\(sum\)数组求出整个区间某个数的个数,最后在与\(p[x + 1][y - 1]\),比较一下就好了,最多扫\(2 *\sqrt n\)个数,复杂度\(O( \sqrt n)\)

#include <bits/stdc++.h>

using namespace std;

inline long long read() {
    long long s = 0, f = 1; char ch;
    while(!isdigit(ch = getchar())) (ch == '-') && (f = -f);
    for(s = ch ^ 48;isdigit(ch = getchar()); s = (s << 1) + (s << 3) + (ch ^ 48));
    return s * f;
}

const int N = 4e4 + 5;
int n, m, t, len, last;
int a[N], c[N], vis[N], pos[N], tong[N], pre[N], sum[205][N];
struct block { int l, r; } b[N];
struct number { int num, x; } p[205][205];

void make_pre() {
    for(int i = 1;i <= t; i++) {
        number tmp; tmp.num = tmp.x = 0;
        for(int j = i;j <= t; j++) {
            for(int k = b[j].l;k <= b[j].r; k++) {
                tong[a[k]]++;
                if(tong[a[k]] > tmp.num) {
                    tmp.num = tong[a[k]]; tmp.x = a[k];
                }
                else if(tong[a[k]] == tmp.num) {
                    tmp.x = min(tmp.x, a[k]);
                }
            }
            p[i][j] = tmp; 
        }
        for(int j = i;j <= t; j++) 
            for(int k = b[j].l;k <= b[j].r; k++) tong[a[k]] = 0;
    }
    for(int i = 1;i <= t; i++) {
        for(int j = 1;j <= n; j++) sum[i][a[j]] = sum[i - 1][a[j]];
        for(int j = b[i].l;j <= b[i].r; j++) sum[i][a[j]] ++;
    }
}

int query(int l, int r) {
    int x = pos[l], y = pos[r];
    if(y - x <= 2) {
        int tmp = 0;
        for(int i = l;i <= r; i++) tong[a[i]] = 0;
        for(int i = l;i <= r; i++) {
            tong[a[i]] ++;
            if(tong[a[i]] > tong[tmp]) tmp = a[i];
            else if(tong[a[i]] == tong[tmp]) tmp = min(tmp, a[i]);
        }
        return pre[tmp];
    }
    else {
        int ans = p[x + 1][y - 1].x, res_num = 0, res_x = 0;
        tong[ans] = vis[ans] = 0;  
        for(int i = l;i <= b[x].r; i++) tong[a[i]] = 0, vis[a[i]] = 0;
        for(int i = b[y].l;i <= r; i++) tong[a[i]] = 0, vis[a[i]] = 0;
        for(int i = l;i <= b[x].r; i++) tong[a[i]] ++;
        for(int i = b[y].l;i <= r; i++) tong[a[i]] ++;
        for(int i = l;i <= b[x].r; i++) {
            if(!vis[a[i]]) {
                vis[a[i]] = 1;
                int tmp = tong[a[i]] + sum[y - 1][a[i]] - sum[x][a[i]];
                if(res_num < tmp) res_num = tmp, res_x = a[i];
                else if(res_num == tmp) res_x = min(res_x, a[i]);
            }
        }  
        for(int i = b[y].l;i <= r; i++) {
            if(!vis[a[i]]) {
                vis[a[i]] = 1;
                int tmp = tong[a[i]] + sum[y - 1][a[i]] - sum[x][a[i]];
                if(res_num < tmp) res_num = tmp, res_x = a[i];
                else if(res_num == tmp) res_x = min(res_x, a[i]);
            }
        }
        int tmp = tong[ans] + p[x + 1][y - 1].num;
        if(res_num > tmp) ans = res_x;
        else if(res_num == tmp) ans = min(ans, res_x);
        return pre[ans];
    }
}

int main() {
    
    n = read(); m = read(); len = sqrt(n); t = (n - 1) / len + 1;
    for(int i = 1;i <= n; i++) a[i] = c[i] = read(), pos[i] = (i - 1) / len + 1, b[pos[i]].l = 2333333;
    for(int i = 1;i <= n; i++) b[pos[i]].l = min(b[pos[i]].l, i), b[pos[i]].r = max(b[pos[i]].r, i);
    sort(c + 1, c + n + 1);
    int cnt = unique(c + 1, c + n + 1) - c - 1;
    for(int i = 1;i <= n; i++) {
        int tmp = a[i];
        a[i] = lower_bound(c + 1, c + cnt + 1, a[i]) - c;
        pre[a[i]] = tmp;
    }
    make_pre(); 
    for(int i = 1, l, r;i <= m; i++) {
        l = read(); r = read();
        l = (last + l - 1) % n + 1; r = (last + r - 1) % n + 1;
        if(l > r) swap(l, r);
        printf("%d\n", last = query(l, r));
    }

    return 0;
}
posted @ 2020-09-24 22:29  C锥  阅读(88)  评论(0编辑  收藏  举报