牛客練習賽10 E題 數列查找 (分塊思想 + 莫隊算法)
阿新 • • 發佈:2018-02-10
意義 blog str aps mes blank ref pair rem
題目鏈接 數列查找
考慮分塊然後跑莫隊,
設$c[i]$為$i$在當前維護的區間內出現的次數,
$g[i]$為在當前維護的區間內有多少個數出現次數為$i$,
$bg[i]$把出現次數分塊,$bg[i]$的意義是第$i$個塊代表的所有出現次數中出現的個數。
$f[i][j]$對$1$到$n$分塊,意義為當前在第$j$個數字塊中有多少個數出現次數為$i$。
每一次詢問的時候,我們先求出當前要求的出現次數是多少。
這個通過$bg[]$來求。
然後再根據$f[][]$確定當前區間中出現$k1$次的所有數中第$k2$小的數。
為了方便我用了離散化。
時間復雜度$O(m\sqrt{n} + n\sqrt{n})$
#include <bits/stdc++.h> using namespace std; #define rep(i, a, b) for (int i(a); i <= (b); ++i) #define dec(i, a, b) for (int i(a); i >= (b); --i) #define MP make_pair #define fi first #define se second typedef long long LL; const int N = 4e4 + 10; const int M = 203; int belong[N]; int c[N], g[N], bg[N]; int f[N][M]; int l, r, kth; int blocknum; int L[M], R[M], ret[N]; struct node{ int l, r, x, y, id; void scan(){ scanf("%d%d%d%d", &l, &r, &x, &y); } friend bool operator < (const node &a, const node &b){ return belong[a.l] == belong[b.l] ? a.r < b.r : belong[a.l] < belong[b.l]; } } q[N]; int a[N], val[N]; int bs, cnt; int n, m; void remove(int x, int y){ --f[y][belong[x]]; if (g[y] == 1) --bg[belong[y]]; --g[y]; } void add(int x, int y){ ++f[y][belong[x]]; if (g[y] == 0) ++bg[belong[y]]; ++g[y]; } int solve(int i){ int num = 0; rep(j, 1, blocknum){ num += bg[j]; if (num >= q[i].x){ num -= bg[j]; rep(k, L[j], R[j]){ num += (int)(g[k] > 0); if (num == q[i].x) return k; } } } return 0; } int calc(int i, int x){ int num = 0; rep(j, 1, blocknum){ num += f[x][j]; if (num >= q[i].y){ num -= f[x][j]; rep(k, L[j], R[j]){ num += (int)(c[k] == x); if (num == q[i].y) return k; } } } return 0; } int main(){ scanf("%d", &n); rep(i, 1, n) scanf("%d", a + i), val[i] = a[i], q[i].id = i; sort(val + 1, val + n + 1); cnt = unique(val + 1, val + n + 1) - val - 1; rep(i, 1, n) a[i] = lower_bound(val + 1, val + cnt + 1, a[i]) - val; bs = sqrt(n); rep(i, 1, n) belong[i] = (i - 1) / bs + 1; blocknum = belong[n]; rep(i, 1, blocknum) L[i] = 1e9, R[i] = 0; rep(i, 1, n){ L[belong[i]] = min(L[belong[i]], i); R[belong[i]] = max(R[belong[i]], i); } scanf("%d", &m); rep(i, 1, m) q[i].scan(); sort(q + 1, q + m + 1); rep(i, 1, n) add(a[i], 0); l = 1, r = 0; rep(i, 1, m){ while (r < q[i].r){ ++r; remove(a[r], c[a[r]]); ++c[a[r]]; add(a[r], c[a[r]]); } while (r > q[i].r){ remove(a[r], c[a[r]]); --c[a[r]]; add(a[r], c[a[r]]); --r; } while (l > q[i].l){ --l; remove(a[l], c[a[l]]); ++c[a[l]]; add(a[l], c[a[l]]); } while (l < q[i].l){ remove(a[l], c[a[l]]); --c[a[l]]; add(a[l], c[a[l]]); ++l; } kth = solve(i); ret[q[i].id] = val[calc(i, kth)]; } rep(i, 1, m) printf("%d\n", ret[i]); return 0; }
牛客練習賽10 E題 數列查找 (分塊思想 + 莫隊算法)