题意:
查询区间 ([l,r]) 内一个数乘上它在区间出现次数的最大值
使用莫队的时候进行增加操作的时候会很简单,但是在删除操作的时候不是那么好维护的时候,可以使用不删除的莫队(回滚莫队)
还是相同的思路,先把询问排序
然后对于左端点在同一个块的询问来说
如图
如果右端点也在块内,则暴力计算
否则左端点从下一个块的左边开始,右端点单调向右移动。
左端点在块内反复进行回滚操作。
这样就在保证时间复杂度还是 (O(nsqrt n)) 的情况下避免了删除操作
/*
* @Author: zhl
* @Date: 2020-11-19 10:38:35
*/
#include<bits/stdc++.h>
using namespace std;
using ll = long long;
const int N = 1e5 + 10;
int n, m, len, cnt[N], nums[N], w[N], ID[N];
ll ans[N];
struct Query {
int id, l, r;
bool operator < (const Query& rhs)const {
int al = ID[l], bl = ID[rhs.l];
if (al != bl)return al < bl;
return r < rhs.r;
}
}q[N];
void add(int x, ll& res) {
cnt[x]++;
res = max(res, 1ll * cnt[x] * nums[x]);
}
int main() {
scanf("%d%d", &n, &m);
int numID = 0;
for (int i = 1; i <= n; i++)scanf("%d", w + i), nums[++numID] = w[i];
sort(nums + 1, nums + 1 + n);
numID = unique(nums + 1, nums + 1 + n) - nums - 1;
len = sqrt(n);
for (int i = 1; i <= n; i++)ID[i] = i / len;
for (int i = 1; i <= n; i++)w[i] = lower_bound(nums + 1, nums + 1 + numID, w[i]) - nums;
for (int i = 1; i <= m; i++) {
scanf("%d%d", &q[i].l, &q[i].r);
q[i].id = i;
}
sort(q + 1, q + 1 + m);
for (int x = 1; x <= m;) {
int y = x;
while (y <= m and ID[q[y].l] == ID[q[x].l]) y++;
//块内暴力
int right = len * ID[q[x].l] + len;
//int right = len * ID[q[y].l]; 这样不对,y不一定比x大
while (x < y and q[x].r <= right - 1) {
ll res = 0;
for (int i = q[x].l; i <= q[x].r; i++) add(w[i], res);
ans[q[x].id] = res;
for (int i = q[x].l; i <= q[x].r; i++) cnt[w[i]]--;
x++;
}
//块外
int l = right, r = right - 1;
ll res = 0;
while (x < y) {
int ql = q[x].l, qr = q[x].r;
while (r < qr)add(w[++r], res);
ll _res = res;
while (l > ql)add(w[--l], res);
ans[q[x].id] = res;
while (l < right) cnt[w[l++]] --;
res = _res;
x++;
}
memset(cnt, 0, sizeof cnt);
}
for (int i = 1; i <= m; i++)printf("%lld
", ans[i]);
}
给定一个序列,多次询问一段区间 ([l,r]),求区间中相同的数的最远间隔距离。
序列中两个元素的间隔距离指的是两个元素下标差的绝对值。
这个说是模板题,其实上一道题更模板。
#include<bits/stdc++.h>
using namespace std;
const int N = 2e5 + 10;
int w[N], ans[N], n, m, nums[N], ID[N], len;
int fir[N], last[N];
int mfir[N], mlast[N], mpos[N], mcnt, vis[N], vscnt;
struct Query {
int id, l, r;
bool operator < (const Query& b)const {
if (ID[l] != ID[b.l])return ID[l] < ID[b.l];
return r < b.r;
}
}q[N];
void add(int pos, int val, int& res) {
if (!fir[val]) fir[val] = pos;
else fir[val] = min(fir[val], pos);
if (!last[val])last[val] = pos;
else last[val] = max(last[val], pos);
res = max(res, last[val] - fir[val]);
}
int main() {
scanf("%d", &n);
int numID = 0;
for (int i = 1; i <= n; i++)scanf("%d", w + i), nums[++numID] = w[i];
sort(nums + 1, nums + 1 + n);
numID = unique(nums + 1, nums + 1 + n) - nums - 1;
for (int i = 1; i <= n; i++)w[i] = lower_bound(nums + 1, nums + 1 + numID, w[i]) - nums;
len = sqrt(n);
for (int i = 1; i <= n; i++)ID[i] = i / len;
scanf("%d", &m);
for (int i = 1; i <= m; i++) {
scanf("%d%d", &q[i].l, &q[i].r); q[i].id = i;
}
sort(q + 1, q + 1 + m);
for (int x = 1; x <= m;) {
int y = x;
while (y <= m and ID[q[y].l] == ID[q[x].l])y++;
int right = ID[q[x].l] * len + len;
while (x < y and q[x].r <= right - 1) {
int res = 0, mcnt = 0; vscnt++;
for (int i = q[x].l; i <= q[x].r; i++) {
if (vis[w[i]] != vscnt) {
vis[w[i]] = vscnt;
mpos[++mcnt] = w[i];
mfir[mcnt] = fir[w[i]];
mlast[mcnt] = last[w[i]];
}
add(i, w[i], res);
}
ans[q[x].id] = res;
for (int i = 1; i <= mcnt; i++) {
fir[mpos[i]] = mfir[i];
last[mpos[i]] = mlast[i];
}
x++;
}
int l = right, r = right - 1;
int res = 0;
while (x < y) {
int ql = q[x].l, qr = q[x].r;
while (r < qr)r++, add(r, w[r], res);
int _res = res;
mcnt = 0; vscnt++;
while (l > ql) {
l--;
if (vis[w[l]] != vscnt) {
vis[w[l]] = vscnt;
mpos[++mcnt] = w[l];
mfir[mcnt] = fir[w[l]];
mlast[mcnt] = last[w[l]];
}
add(l, w[l], res);
}
ans[q[x].id] = res;
for (int i = 1; i <= mcnt; i++) {
fir[mpos[i]] = mfir[i];
last[mpos[i]] = mlast[i];
}
l = right; res = _res;
x++;
}
memset(fir, 0, sizeof fir); memset(last, 0, sizeof last);
}
for (int i = 1; i <= m; i++)printf("%d
", ans[i]);
}