「SDOI2009」 HH的项链 - 莫队

题目大意

给定一个序列以及M个询问(L,R),求[L,R]内不同的数的个数。

分析

先将询问记录下来,按照左端点排序,再将询问分成\sqrt{m}块,每块内部按照右端点排序。用两个指针pl,pr,开始pl=1,pr=0,在按照排序后结果遍历每个询问的时候不断去更新两个指针,使它们指向当前询问的l,r,在移动过程中记录下每个数字出现的次数,并不断更新答案,结束后将当前的答案记录到数组对应位置上。

具体看代码。

当然,此题离线+树状数组可过且速度快于莫队。

代码

#include <iostream>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <map>
#include <queue>
using namespace std;
struct qt {
	int l,r,num;
}q[200005];
int n,len,a[50005],m,ans[200005],mp[1001001];
int app[50500],pl,pr,temp,tot;
bool cmp(qt a,qt b) {
	if ((a.l-1)/len!=(b.l-1)/len) return (a.l-1)/len<(b.l-1)/len;
	return a.r<b.r;
}
inline void update(int x) {
	app[x]++;
	if (app[x]==1) temp++;//当有一个数字出现次数从0->1,就说明ans+=1 
}
inline void downdate(int x) {
	app[x]--;
	if (app[x]==0) temp--;//当有一个数字出现次数变为了0,就说明ans-=1 
}
int main() {
	scanf("%d",&n);
	for (int i=1;i<=n;i++) {
		scanf("%d",&a[i]);
		if (!mp[a[i]]) mp[a[i]]=++tot;//离散化 
		a[i]=mp[a[i]];
	}
	scanf("%d",&m);
	for (int i=1;i<=m;i++)
		scanf("%d%d",&q[i].l,&q[i].r),q[i].num=i;
	len=sqrt(n);
	sort(q+1,q+m+1,cmp);
	pl=1,pr=0;
	for (int i=1;i<=m;i++) {
		while (pr<q[i].r)
			update(a[++pr]);
		while (pl>q[i].l)
			update(a[--pl]);
		while (pr>q[i].r)
			downdate(a[pr--]);
		while (pl<q[i].l)
			downdate(a[pl++]);
		ans[q[i].num]=temp;
	}
	for (int i=1;i<=m;i++)
		printf("%d\n",ans[i]);
	return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值