bzoj 1878: [SDOI2009]HH的项链【树状数组】

对于一个lr,每个颜色贡献的是在(1,r)区间里出现的最右位置,所以记录一个b数组表示当前点这个颜色上一个出现的位置
然后把询问离线,按r升序排序
每次把右端点右移,把这个点在树状数组上+1,并且在当前这个点的b位置上-1(表示没用了),然后树状数组前缀和减一下即可
我写的莫队会T

#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
const int N=1000005;
int n,m,a[N],b[N],la[N],t[N],ans[N];
struct qwe
{
	int l,r,id;
}q[N];
bool cmp(const qwe &a,const qwe &b)
{
	return a.r<b.r;
}
int read()
{
	int r=0,f=1;
	char p=getchar();
	while(p>'9'||p<'0')
	{
		if(p=='-')
			f=-1;
		p=getchar();
	}
	while(p>='0'&&p<='9')
	{
		r=r*10+p-48;
		p=getchar();
	}
	return r*f;
}
void update(int x,int w)
{
	if(x==0)
		return;
	for(int i=x;i<=n;i+=(i&(-i)))
		t[i]+=w;
}
int ques(int x)
{
	int r=0;
	for(int i=x;i>=1;i-=(i&(-i)))
		r+=t[i];
	return r;
}
int main()
{
	n=read();
	for(int i=1;i<=n;i++)
		a[i]=read(),b[i]=la[a[i]],la[a[i]]=i;
	m=read();
	for(int i=1;i<=m;i++)
		q[i].l=read(),q[i].r=read(),q[i].id=i;
	sort(q+1,q+1+m,cmp);
	int r=0;
	for(int i=1;i<=m;i++)
	{
		while(r<q[i].r)
			r++,update(b[r],-1),update(r,1);
		ans[q[i].id]=ques(q[i].r)-ques(q[i].l-1);
	}
	for(int i=1;i<=m;i++)
		printf("%d\n",ans[i]);
	return 0;
}
posted @ 2018-07-29 10:08  lokiii  阅读(112)  评论(0编辑  收藏  举报