1. 程式人生 > 實用技巧 >回滾莫隊(不刪除莫隊)

回滾莫隊(不刪除莫隊)

AT1219 歴史の研究 - 洛谷

題意

查詢區間 \([l,r]\) 內一個數乘上它在區間出現次數的最大值

使用莫隊的時候進行增加操作的時候會很簡單,但是在刪除操作的時候不是那麼好維護的時候,可以使用不刪除的莫隊(回滾莫隊)

還是相同的思路,先把詢問排序

然後對於左端點在同一個塊的詢問來說

如圖

如果右端點也在塊內,則暴力計算

否則左端點從下一個塊的左邊開始,右端點單調向右移動。

左端點在塊內反覆進行回滾操作。

這樣就在保證時間複雜度還是 \(O(n\sqrt 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\n", ans[i]);
}

P5906 【模板】回滾莫隊&不刪除莫隊 - 洛谷

給定一個序列,多次詢問一段區間 \([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\n", ans[i]);
}