LOJ数列分块 9 题解

\(1.\) 题意

给定一个长度 \(n\) 序列,每次查询区间 \(l, r\) 的众数。

\(2.\) 思路

如果边界是 \([l,r]\)\(l\) 在第 \(a\) 块,\(r\) 在第 \(b\) 块,可以分成三个部分:

  1. \(l\)\(a\) 最后一块
  2. \([a+1→b−1]\)
  3. \(b\) 块到 \(r\)

根据上面的性质,如果我们预先处理 \([a+1→b−1]\) 块的众数,再去遍历判断第一部分和第三部分是否有更合适的众数,这道题就能做出来了。

#include <map>
#include <cmath>
#include <queue>
#include <vector>
#include <cstdio>
#include <string>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <unordered_map>
#pragma GCC optimize("O3")
#pragma G++ optimize("O3")
#pragma GCC optimize(3, "Ofast", "inline")
#pragma GCC optimize("no-stack-protector")
#define int long long
using namespace std;

template <class T> inline void read(T &x){
    x = 0; register char c = getchar(); register bool f = 0;
    while (!isdigit(c)) f ^= c == '-', c = getchar();
    while (isdigit(c)) x = x * 10 + c - '0', c = getchar();
    if (f) x = -x;
}

template <class T> inline void print(T x){
    if (x < 0) putchar('-'), x = -x;
    if (x > 9) print(x / 10);
    putchar('0' + x % 10);
}

const int N = 2e5 + 10;
const int M = 1e3 + 10;
int n, b, tot, a[N], id[N], val[N], cnt[N], dp[M][M];
vector<int> block[N];
unordered_map<int,int> mp;

inline void init(int pos){
    memset(cnt, 0, sizeof cnt);
    int maxx = 0, ans = 0;
    for(int i = (pos - 1) * b + 1; i <= n; i ++){
        cnt[a[i]] ++;
        if(cnt[a[i]] > maxx || (cnt[a[i]] == maxx && val[a[i]] < val[ans])) ans = a[i], maxx = cnt[a[i]];
        dp[pos][id[i]] = ans;
    }
}

inline int getlen(int l, int r, int x){
    return upper_bound(block[x].begin(), block[x].end(), r) - lower_bound(block[x].begin(), block[x].end(), l);
}

int query(int l, int r){
    register int ans, maxx;
    ans = dp[id[l] + 1][id[r] - 1];
    maxx = getlen(l, r, ans);
    for(register int i = l; i <= min(id[l] * b, r); i++){
        int tmp = getlen(l, r, a[i]);
        if(tmp > maxx || (tmp == maxx && val[a[i]] < val[ans]))
            ans = a[i], maxx = tmp;
    }
    if(id[l] == id[r]) return ans;  
    for(register int i = (id[r] - 1) * b + 1; i <= r; i++){
        int tmp = getlen(l, r, a[i]);
        if(tmp > maxx || (tmp == maxx && val[a[i]] < val[ans]))
            ans = a[i], maxx = tmp;
    }
    return ans;
}

signed main(){
    read(n); b = 100;
    for(int i = 1; i <= n; i ++){
        read(a[i]);
        if(mp[a[i]] == 0) mp[a[i]] = ++ tot, val[tot] = a[i];
        a[i] = mp[a[i]];
        block[a[i]].push_back(i);
    }
    for(int i = 1; i <= n; i ++) id[i] = (i - 1) / b + 1;
    for(int i = 1; i <= id[n]; i ++) init(i);
    for(int i = 1, l, r; i <= n; i ++){
        read(l), read(r);
        print(val[query(l, r)]), puts("");
    }
    return 0;
}

posted @ 2022-06-07 10:50  Altwilio  阅读(21)  评论(0编辑  收藏  举报