为什么下面的排序方法不对呢,普通莫队和带修莫队按照下面那种规则就是对的呢qwq?
struct query {
int l, r, id;
bool operator<(const query &rhs) const {
if (bel[l] != bel[rhs.l]) return l < rhs.l;
return r < rhs.r;
// if (l / len != rhs.l / len) return l < rhs.l;
// if (l / len & 1) return r < rhs.r;
// else return r > rhs.r;
}
} Q[N];
完整代码:
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
const int N = 100010;
int n, q, a[N], b[N]; // b存储离散化后的数组
vector<int> alls;
int bel[N], L[N], R[N], len, sq;
int cnt[N], __cnt[N]; // __cnt用来暴力求块内的查询
ll ans[N], Ans; // Ans是当前区间的答案
struct query {
int l, r, id;
bool operator<(const query &rhs) const {
if (bel[l] != bel[rhs.l]) return l < rhs.l;
return r < rhs.r;
// if (l / len != rhs.l / len) return l < rhs.l;
// if (l / len & 1) return r < rhs.r;
// else return r > rhs.r;
}
} Q[N];
void init ()
{
sq = sqrt(n);
len = n / sq;
for (int i = 1; i <= sq; i ++ ) {
L[i] = (i - 1) * len + 1;
R[i] = i * len;
}
if (R[sq] < n) {
sq ++ ;
L[sq] = R[sq-1] + 1;
R[sq] = n;
}
// init bel
for (int i = 1; i <= sq; i ++ )
for (int j = L[i]; j <= R[i]; j ++ )
bel[j] = i;
}
void del (int x) {
-- cnt[x];
}
void add (int x, ll &nowAns) {
++ cnt[x];
nowAns = max(nowAns, 1ll * cnt[x] * alls[x]);
}
int main ()
{
scanf("%d%d", &n, &q);
for (int i = 1; i <= n; i ++ ) {
scanf("%d", &a[i]);
alls.push_back(a[i]);
}
for (int i = 1; i <= q; i ++ ) {
int l, r; scanf("%d%d", &l, &r);
Q[i] = { l, r, i };
}
// 离散化
sort(alls.begin(), alls.end());
alls.erase(unique(alls.begin(), alls.end()), alls.end());
for (int i = 1; i <= n; i ++ ) {
b[i] = lower_bound(alls.begin(), alls.end(), a[i]) - alls.begin();
}
init();
sort(Q + 1, Q + q + 1);
int l = 1, r = 0, last_block = 0;
for (int i = 1; i <= q; i ++ ) {
// 如果询问的左右端点在一个块内,O(√m)解决
if (bel[Q[i].l] == bel[Q[i].r]) {
for (int j = Q[i].l; j <= Q[i].r; j ++ ) ++ __cnt[b[j]];
for (int j = Q[i].l; j <= Q[i].r; j ++ ) {
ans[Q[i].id] = max(ans[Q[i].id], 1ll * __cnt[b[j]] * alls[b[j]]);
}
for (int j = Q[i].l; j <= Q[i].r; j ++ ) -- __cnt[b[j]];
continue;
}
// 如果上一个块和左端点的块不同,重新设置l和r
// l = R + 1, r = R
// 因为这里需要的是只增不缩的回滚莫队,所以要把l设置为最大值,然后往外拓展
if (last_block != bel[Q[i].l]) {
while(l < R[bel[Q[i].l]] + 1) del(b[l ++ ]);
while(r > R[bel[Q[i].l]]) del(b[r -- ]);
Ans = 0;
last_block = bel[Q[i].l];
}
// 直接修改右区间
while(r < Q[i].r) add(b[++ r], Ans);
// 注意修改作左区间需要回滚,不能真正修改,我们用一个tmp来维护答案
int __l = l;
ll tmp = Ans;
// 使用临时变量 __l 和 tmp 来更新
while(__l > Q[i].l) add(b[-- __l], tmp);
ans[Q[i].id] = tmp;
// 使用 __l 和 l 来实现回滚操作
while(__l < l) del(b[__l ++ ]);
}
for (int i = 1; i <= q; i ++ ) {
printf("%lld\n", ans[i]);
}
return 0;
}