【莫队】luogu_1972 BZOJ_1878 [SDOI2009]HH的项链

博客围绕一个序列的M个询问展开,每次询问求l∼r之间的权值种类。采用莫队算法,将询问分块排序,通过分析右指针和左指针的移动情况,把时间复杂度从O(nm)优化成O(n∗n),还使用奇偶性排序进一步优化,并给出了代码。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题意

一个序列,MMM个询问,每次求l∼rl\sim rlr之间的权值种类。

思路

莫队算法,将询问分成n\sqrt{n}n块,对于询问,如果lll在同一个块内,就根据rrr升序排序。

根据这样排序后暴力,时间复杂度可从O(nm)O(nm)O(nm)优化成O(n∗n)O(n*\sqrt{n})O(nn)

最重要的。让我们先谈论右指针。对于每个块,查询是递增的顺序排序,所以右指针(currentRcurrentRcurrentR)按照递增的顺序移动。在下一个块的开始时,指针可能在extreme endextreme\ endextreme end(最右端?) ,将移动到下一个块中的最小的RRR处。这意味着对于一个给定的块,右指针移动的量是O(N)O(N)ON。我们有O(N)O(\sqrt{N})ON块,所以总共是O(N∗N)O(N∗\sqrt{N})ONN)。太好了!

让我们看看左指针怎样移动。对于每个块,所有查询的左指针落在同一个块中,当我们从一个查询移动到另个一查询左指针会移动,但由于前一个LLL与当前的LLL在同一块中,此移动是O(N)O(\sqrt{N})ON(块大小)的。在每一块中左指针的移动总量是O(Q∗N),QO(Q∗\sqrt{N}),QOQNQ是落在那个块的查询的数量。对于所有的块,总的复杂度为O(M∗N)O(M*\sqrt{N})OMN

就是这样,总复杂度为O((N+M)∗sqrtN)=O(N∗N)O((N+M)∗sqrt{N})=O(N∗\sqrt{N})O((N+M)sqrtN)=O(NN)

这里用了奇偶性排序,可以优化复杂度。

代码

#include<cmath>
#include<cstdio>
#include<algorithm>

struct node {
	int l, r, pos;
}que[500001];
int n, m, block, ans;
int a[500001], cnt[1000001], res[500001];

bool operator <(const node &x, const node &y) {
	return (x.l / block) ^ (y.l / block) ? x.l < y.l : (((x.l / block) & 1) ? x.r < y.r : x.r > y.r);
}

void add(int x) {
	if (++cnt[a[x]] == 1) ans++;
}

void del(int x) {
	if (!--cnt[a[x]]) ans--;
}

int main() {
	scanf("%d", &n);
	for (int i = 1; i <= n; i++)
		scanf("%d", &a[i]);
	scanf("%d", &m);
	block = n / sqrt(m * 2 / 3);
	for (int i = 1; i <= m; i++)
		scanf("%d %d", &que[i].l, &que[i].r), que[i].pos = i;
	std::sort(que + 1, que + m + 1);
	int l = 0, r = 0;
	for (int i = 1; i <= m; i++) {
		int ql = que[i].l, qr = que[i].r;
        while (l < ql) del(l++);
        while (l > ql) add(--l);
        while (r < qr) add(++r);
        while (r > qr) del(r--);
        res[que[i].pos] = ans;
	}
	for (int i = 1; i <= m; i++)
		printf("%d\n", res[i]);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值