AT_abc242_g

In Luogu

做法

一道挺板子的莫队。

所谓莫队算法,其实就是暴力算法的优化。暴力算法是按询问的左右端点排序,然后暴力得到答案的,而莫队是把询问左右端点所属的块进行排序,再与暴力一样得到答案。优化后,时间复杂度变成了 \(\mathcal{O(n \sqrt n)}\)

再回到这道题。我们将询问离线,分块,接着按左右端点属于的块进行排序,最后暴力得到答案。

code:

#include <bits/stdc++.h>
#define int long long

const int N = 5e5 + 5, M = 1e6 + 5, MOD = 1000007;

using namespace std;

inline int read(){
    int x = 0, f = 1; char c = getchar();
    while (c < '0' || c > '9') { if (c == '-') f = -1; c = getchar(); }
    while (c >= '0' && c <= '9') { x = x * 10 + c - '0'; c = getchar(); }
    return x * f;
} 

int n, m, len, res;

int f[N], cnt[N], ans[M];

struct query

{
	int l, r, id;
}q[M];

bool cmp (query x, query y)

{
	return (x.r / len) == (y.r / len) ? x.l < y.l : x.r < y.r;
}

void del(int k)

{
	res -= (cnt[f[k]] / 2);
	cnt[f[k]] --;
	res += (cnt[f[k]] / 2);
}

void add(int k)

{
	res -= (cnt[f[k]] / 2);
	cnt[f[k]] ++;
	res += (cnt[f[k]] / 2);
}

signed main()

{
	n = read();
	for (int i = 1; i <= n; i ++ ) f[i] = read();
	m = read();
	for (int i = 1, x, y; i <= m; i ++ ) 
	{
		x = read(), y = read();
		q[i] = {x, y, i};
	}
	len = n / (sqrt((m * 2 / 3)));
	sort(q + 1, q + m + 1, cmp);
	int l = 0, r = 0;
	for (int i = 1; i <= m; i ++ )
	{
		int ql = q[i].l, qr = q[i].r;
		while (l < ql) del(l ++);
		while (r > qr) del(r --);
		while (l > ql) add(-- l);
		while (r < qr) add(++ r);
		ans[q[i].id] = res;
	}
	for (int i = 1; i <= m; i ++ ) cout << ans[i] << '\n';
}
posted @ 2023-07-19 07:56  恋暗  阅读(9)  评论(0)    收藏  举报