A preliminary study on the history of joysc 2014 Day1

Posted by robotta1530 on Wed, 10 Nov 2021 08:13:32 +0100

Roll back Mo team

​ The core of Mo team algorithm is to quickly calculate new results when the interval changes. However, when our sequence (or any other set) can only easily implement one operation in addition or deletion, and the other operation is difficult to implement, it is necessary to roll back the Mo queue by using a variant of the Mo queue algorithm to meet the requirements.

Pre knowledge: ordinary Mo team, divided into blocks

thinking

Take the team that can only be added but not reduced as an example

The key to rollback is that for all queries, the left endpoint is sorted in ascending order (from small to large) according to its block, and the blocks are sorted in ascending order according to the right endpoint at the same time.

For queries where the left and right endpoints are in the same block, violent queries are sufficient, and the complexity \ (O(\sqrt n) \)

Whenever the left endpoint changes, initialize and reset \ (l,r \) to the tail of the left interval block, which are ed[bel[q[i].l]] and ed[bel[q[i].l]] + 1 respectively (note that \ (l \) is larger than \ (r \), and clear the previous query records.

For queries where the left endpoint is in the same block, the right endpoint is incremented (because it is out of order), the right endpoint of the interval is incremented to the right, and the modifications are recorded like ordinary Mo teams. For the left endpoint, first record the answer when the left endpoint is not moving, use a temporary left endpoint variable such as l2 and a temporary answer variable such as t, move the temporary left endpoint, record the modification and update the answer.

When this query is completed, the temporary left endpoint and the temporary answer variable are returned directly to complete the "rollback"

The same is true for queries that can only be reduced but not added. Similarly, the left endpoint is sorted in ascending order (from small to large) according to its block, but when the blocks are the same, the right endpoint is sorted in descending order

When the left endpoint changes, initialize \ (r \) to \ (n \) and \ (l \) to the starting point of the left endpoint block

The latter operation is similar to adding without subtracting

It can be proved that the time complexity of rollback is \ (O(n\sqrt n) \)

Examples

#2874. "Joysc 2014 Day1" historical research - topic - LibreOJ (loj.ac)

Roll back Mo team template question

There are two schemes for recording x, one is to discretize after reading in, and the other is to use unordered_map (using map will cause timeout)

#include<bits/stdc++.h>
#include<unordered_map>
using namespace std;
using ll = long long;
const ll maxn = 1e5;
ll n;
ll sq;
ll st[maxn + 10];
ll ed[maxn + 10];
ll a[maxn + 10];
ll bel[maxn + 10];
ll ans[maxn + 10];
struct Query {
	ll l, r, id;
}q[maxn+10];
void init(ll n) {
	for (ll i = 1; i <= n; i++)
		cin >> a[i];
	sq = sqrt(n);
	for (ll i = 1; i <= sq; i++) {
		st[i] = n / sq * (i - 1) + 1;
		ed[i] = n / sq * i;
	}
	ed[sq] = n;
	for (ll i = 1; i <= sq; i++) {
		for (ll j = st[i]; j <= ed[i]; j++)
			bel[j] = i;
	}
}
bool cmp(Query a, Query b) {
	if (bel[a.l] != bel[b.l])
		return bel[a.l] < bel[b.l];
	else
		return a.r < b.r;
}
unordered_map<ll, ll> cnt;
void add(ll p, ll& ans) {
	cnt[a[p]]++;
	ans = max(ans, cnt[a[p]] * a[p]);
}
void del(ll p) {
	cnt[a[p]]--;
}
void solve() {
	ll n,Q;
	cin >> n>>Q;
	init(n);
	for (ll i = 1; i <= Q; i++) {
		cin >> q[i].l >> q[i].r;
		q[i].id = i;
	}
	sort(q + 1, q + Q + 1, cmp);
	ll l = 1, r = 0;
	ll curblo = 0;
	ll Max = 0;
	for (ll i = 1; i <= Q; i++) {
		if (bel[q[i].l] == bel[q[i].r]) {
			unordered_map<ll, ll> cnt1;
			for (ll j = q[i].l; j<= q[i].r; j++) 
				cnt1[a[j]]++;
			ll t = 0;
			for (ll j = q[i].l; j <= q[i].r; j++)
				t = max(t, cnt1[a[j]] * a[j]);
			for (ll j = q[i].l; j <= q[i].r; j++)
				cnt1[a[j]]--;
			ans[q[i].id] = t;
			continue;
		}
		if (curblo != bel[q[i].l]) {
			while (r > ed[bel[q[i].l]])
				del(r--);
			while (l < ed[bel[q[i].l]] + 1)
				del(l++);
			curblo = bel[q[i].l];
			Max = 0;
		}
		while (r < q[i].r)
			add(++r, Max);
		ll t = Max;
		ll l2 = l;
		while (l2 > q[i].l)
			add(--l2, t);
		ans[q[i].id] = t;
		while (l2 < l)
			del(l2++);
	}	
	for (ll i = 1; i <= Q; i++) {
		cout << ans[i] << "\n";
	}
}
int main() {
	ios::sync_with_stdio(false);
	cin.tie(0);
	solve();
	return 0;
}

Topics: partitioning