https://loj.ac/problem/6285
如果只查询众数的个数,完全可以莫队,加数时容易维护众数的数量,删除数时,众数的数量要么减1,要么不变,只需再开一个标记数组维护众数的数量即可
根据陈立杰---《区间众数解题报告》实现了下面两种解法
解法一:
块数分成sqrt(n)超时了,150可以过(分块真毒瘤)
#pragma GCC optimize(2)
#include
using namespace std;
const int MAXN = 1e5 + 15;
int a[MAXN], b[MAXN], c[MAXN], vis[MAXN], belong[MAXN], dp[1000][1000], block, n, m, L, R;
void cal(int x) {
int res = 0, cnt = 0;
memset(vis, 0, sizeof(vis));
for (int i = (x - 1) * block + 1; i <= n; ++i) {
vis[c[i]]++;
if (vis[c[i]] > cnt) res = c[i], cnt = vis[c[i]];
else if (vis[c[i]] == cnt && c[i] < res) res = c[i];
dp[x][belong[i]] = res;
}
}
std::vector pos[MAXN];
int Find(int x, int l, int r) {
return upper_bound(pos[x].begin(), pos[x].end(), r) - lower_bound(pos[x].begin(), pos[x].end(), l);
}
int query(int l, int r) {
int res = 0, cnt = 0;
if (belong[l] == belong[r]) {
for (int i = l; i <= r; ++i) {
int tep = Find(c[i], l, r);
if (tep > cnt) cnt = tep, res = c[i];
else if (tep == cnt && c[i] < res) res = c[i];
}
} else {
res = dp[belong[l] + 1][belong[r] - 1];
cnt = Find(res, l, r);
for (int i = l; i <= belong[l] * block; ++i) {
int tep = Find(c[i], l, r);
if (tep > cnt) cnt = tep, res = c[i];
else if (tep == cnt && c[i] < res) res = c[i];
}
for (int i = (belong[r] - 1) * block + 1; i <= r; ++i) {
int tep = Find(c[i], l, r);
if (tep > cnt) cnt = tep, res = c[i];
else if (tep == cnt && c[i] < res) res = c[i];
}
}
return res;
}
inline int read() {
int x = 0, f = 1;
char c = getchar();
for (; !isdigit(c); c = getchar()) if (c == '-') f = -1;
for (; isdigit(c); c = getchar()) x = x * 10 + c - '0';
return x * f;
}
inline void write(int x) {
if (x >= 10) write(x / 10);
putchar(x % 10 + '0');
}
int main() {
n = read();
block = 150, m = n / block + (n % block > 0);
for (int i = 1; i <= n; ++i) a[i] = read(), b[i] = a[i];
sort(b + 1, b + n + 1);
int len = unique(b + 1, b + n + 1) - b;
for (int i = 1; i <= n; ++i) {
c[i] = lower_bound(b + 1, b + len, a[i]) - b;
pos[c[i]].emplace_back(i);
belong[i] = (i - 1) / block + 1;
}
for (int i = 1; i <= m; ++i) cal(i);
for (int i = 1; i <= n; ++i) {
L = read(), R = read();
write(b[query(L, R)]);
putchar('\n');
}
return 0;
}
优化后的解法二:
块数调来调去,不是TLE就是MLE,以后有数据范围小一点的再去试试
#pragma GCC optimize(2)
#include
using namespace std;
const int MAXN = 1e5+15;
const int maxn = 320;
int a[MAXN],b[MAXN],c[MAXN],vis[MAXN],belong[MAXN],Dp[maxn][maxn],num[maxn][maxn],dp[maxn][MAXN],ID[maxn][MAXN],DP[maxn][maxn][maxn],block,n,m,L,R;
map v;
void cal(int x){
for(int i = 1;i <= n; ++i) dp[x][i] = dp[x-1][i];
int l = (x-1)*block+1,r = min(x*block,n),id = 0;
v.clear();
for(int i = l;i <= r; ++i) {
dp[x][c[i]]++;
if(!v[c[i]]) v[c[i]] = ++id;
ID[x][c[i]] = v[c[i]];
for(int j = 0;j <= id; ++j) DP[x][i-l+1][j] = DP[x][i-l][j];
DP[x][i-l+1][v[c[i]]] ++;
}
int res = 0, cnt = 0;
memset(vis, 0, sizeof(vis));
for (int i = (x - 1) * block + 1; i <= n; ++i) {
vis[c[i]]++;
if (vis[c[i]] > cnt) res = c[i], cnt = vis[c[i]];
else if (vis[c[i]] == cnt && c[i] < res) res = c[i];
Dp[x][belong[i]] = res;
num[x][belong[i]] = cnt;
}
}
int query(int l,int r){
int res = 0,cnt = 0;
if(belong[l] == belong[r]){
int x = belong[l],xL = (x-1)*block+1;
for(int i = l;i <= r; ++i){
int tep = DP[x][r-xL+1][ID[x][c[i]]] - DP[x][l-xL][ID[x][c[i]]];
if(tep > cnt || (tep==cnt&&c[i] cnt || (tep==cnt&&c[i] cnt || (tep==cnt&&c[i]= 10) write(x / 10);
putchar(x % 10 + '0');
}
int main(){
n = read();
block = sqrt(n*1.0),m = n/block + (n%block > 0);
for(int i = 1;i <= n; ++i) a[i] = read(),b[i] = a[i];
sort(b+1,b+n+1);
int len = unique(b+1,b+n+1) - b;
for(int i = 1;i <= n; ++i){
c[i] = lower_bound(b+1,b+len,a[i]) - b;
belong[i] = (i-1)/block + 1;
}
for(int i = 1;i <= m; ++i) cal(i);
for(int i = 1;i <= n; ++i){
L = read(),R = read();
write(b[query(L,R)]);
putchar('\n');
}
return 0;
}