給出乙個數列,和若干詢問,每個詢問讓你求乙個區間內的眾數
6 3
1 2 3 2 1 2
1 5
3 6
1 5
1
2 1
1⩽n
⩽4×1
04,1
⩽m⩽5
×104
,1⩽a
i⩽10
91\leqslant n \leqslant 4\times 10^4,1\leqslant m \leqslant 5\times 10^4,1\leqslant a_i \leqslant 10^9
1⩽n⩽4×
104,
1⩽m⩽
5×10
4,1⩽
ai⩽
109對於求區間眾數,線段樹不易維護
考慮分塊
先對數列a離散化
然後列舉一遍數列a,求出num
i,
jnum_
numi,j
(前i個塊中j顏色出現的次數),時間o(n
n)
o(n\sqrt)
o(nn)
然後求一段連續塊的眾數,先列舉左段的塊,然後暴力搜右節點,時間o(n
n)
o(n\sqrt)
o(nn)
然後對於每次查詢,暴力列舉不在整乙個塊的數
#include
#include
#include
#include
#include
#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];
intmain()
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)}if
(g < nm)
for(
int i =
1; i <= nm;
++i)
}memset
(p,0
,sizeof
(p))
; g =0;
while
(m--
)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)
for(
int i =
max(r * nn +1,
1); i <= y;
++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]);
}return0;
}
分塊 (查詢區間最小眾數
題目鏈結 1 include2 include3 include4 include5 include6 include 7 include8 include9 include10 include11 include12 include13 include14 include 15 include16...
數列分塊入門9 區間眾數
原題 題解 基本題意求 l,r 的最小眾數,對於集合 a,b 顯然 mode a and b 屬於 mode a and b。這樣就可以分塊,預處理f i j 表示i j的眾數。每次查詢時暴力查詢頭尾兩塊的數和中間塊的眾數就可以,關於查詢x在 l,r 出現了幾次,用動態陣列存放x的下標,二分查詢就好...
BZOJ2724 蒲公英 題解(分塊 區間眾數)
題目鏈結 題目大意 給定一段長度為 n 的序列和 m 次詢問,每次詢問區間 l,r 內的最小的眾數。n leq 40000,a i leq 10 9 因為 a i leq 10 9 顯然不能開那麼大的陣列。所以要離散化。對於離散化後的陣列,我們維護兩個值 sum i j 和 p i j sum i ...