【分块】区间众数(金牌导航 分块-1)
生活随笔
收集整理的這篇文章主要介紹了
【分块】区间众数(金牌导航 分块-1)
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
區間眾數
金牌導航 分塊-1
題目大意
給出一個數列,和若干詢問,每個詢問讓你求一個區間內的眾數
輸入樣例
6 3 1 2 3 2 1 2 1 5 3 6 1 5輸出樣例
1 2 1數據范圍
1?N?4×104,1?M?5×104,1?ai?1091\leqslant N \leqslant 4\times 10^4,1\leqslant M \leqslant 5\times 10^4,1\leqslant a_i \leqslant 10^91?N?4×104,1?M?5×104,1?ai??109
解題思路
對于求區間眾數,線段樹不易維護
考慮分塊
先對數列a離散化
然后枚舉一遍數列a,求出numi,jnum_{i,j}numi,j?(前i個塊中j顏色出現的次數),時間O(nn)O(n\sqrt{n})O(nn?)
然后求一段連續塊的眾數,先枚舉左段的塊,然后暴力搜右節點,時間O(nn)O(n\sqrt{n})O(nn?)
然后對于每次查詢,暴力枚舉不在整一個塊的數
代碼
#include<cmath> #include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #define ll long long #define N 40010 #define QN 210 using namespace std; int n, m, x, y, g, L, R, nn, nm, a[N], b[N], p[N], f[QN][QN], num[QN][N]; int main() {scanf("%d%d", &n, &m);for (int i = 1; i <= n; ++i){scanf("%d", &a[i]);b[i] = a[i];}sort(b + 1, b + 1 + n);g = unique(b + 1, b + 1 + n) - b - 1;for (int i = 1; i <= n; ++i)a[i] = lower_bound(b + 1, b + 1 + g, a[i]) - b;nn = sqrt(n);g = 0;nm = n / nn + (n % nn? 1: 0);for (int i = 1; i <= n; ++i){p[a[i]]++;if (i % nn == 0){g++;for (int j = 1; j <= n; ++j)num[g][j] = p[j];}}if (g < nm){for (int j = 1; j <= n; ++j)num[n / nn + 1][j] = p[j];}for (int i = 1; i <= nm; ++i){g = 0;memset(p, 0, sizeof(p));for (int j = (i - 1) * nn + 1; j <= n; ++j){p[a[j]]++;if (p[a[j]] > p[g] || p[a[j]] == p[g] && a[j] < g) g = a[j];if (j % nn == 0) f[i][j / nn] = g;}}memset(p, 0, sizeof(p));g = 0;while(m--){scanf("%d%d", &x, &y);x = (x + b[g] - 1) % n + 1;y = (y + b[g] - 1) % n + 1;if (x > y) swap(x, y);L = (x + nn - 2) / nn + 1;R = y / nn;if (L > R)//沒包含任意一個整的塊直接暴力{g = 0;for (int i = x; i <= y; ++i){p[a[i]]++;if (p[a[i]] > p[g] || p[a[i]] == p[g] && a[i] < g)g = a[i];}for (int i = x; i <= y; ++i)p[a[i]]--;printf("%d\n", b[g]);continue;}g = f[L][R];for (int i = x; i <= min((L - 1) * nn, n); ++i){p[a[i]]++;int X = p[a[i]] + num[R][a[i]] - num[L - 1][a[i]];//加上整的塊里面的int Y = p[g] + num[R][g] - num[L - 1][g];if (X > Y || X == Y && a[i] < g)g = a[i];}for (int i = max(R * nn + 1, 1); i <= y; ++i){p[a[i]]++;int X = p[a[i]] + num[R][a[i]] - num[L - 1][a[i]];int Y = p[g] + num[R][g] - num[L - 1][g];if (X > Y || X == Y && a[i] < g)g = a[i];}for (int i = x; i <= min((L - 1) * nn, n); ++i)//把原來的清掉,不然要O(n),會超時p[a[i]]--;for (int i = max(R * nn + 1, 1); i <= y; ++i)p[a[i]]--;printf("%d\n", b[g]);}return 0; }總結
以上是生活随笔為你收集整理的【分块】区间众数(金牌导航 分块-1)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【高斯消元】球形空间产生器(luogu
- 下一篇: 扎心语录大全