【Luogu P1972】HH的项链

Luogu P1972
一开始非常naive随便打了个树状数组统计就交上去了,然后不出意料的爆零了……
然后删一删改一改过了。
重点:对于区间[1,r]中重复出现的数,我们只需要关心最右边那一个是否在[l,r]中就可以了。
具体思路在代码注释中

#include<cstdio>
#include<algorithm>
using namespace std;
int n,c[1000005],a[1000005],check[1000005],m,maxi,ans[1000005];
struct data
{
	int l,r,id;
	bool operator < (const data&a) const&
	{
		return a.r>r;
	}//重载运算符,使询问的区间r从小到大排序
}q[1000005];
int lowbit(int x)
{
	return x&-x;
}
void add(int x,int num)
{
	while (x<=n)
	{
		c[x]+=num;
		x+=lowbit(x);
	}
}
int query(int x)
{
	int sum=0;
	while (x>0)
	{
		sum+=c[x];
		x-=lowbit(x);	
	}	
	return sum;
}
//树状数组基本操作,不再赘述。
int main()
{
	scanf("%d",&n);
	for (int i=1;i<=n;i++) 
		scanf("%d",&a[i]);
	scanf("%d",&m);
	for (int i=1;i<=m;i++)
	{
		scanf("%d%d",&q[i].l,&q[i].r);
		q[i].id=i;//离线操作
	}
	sort(q+1,q+1+m);
	int tmp=1;
	for (int i=1;i<=m;i++)
	{	
		for (int j=tmp;j<=q[i].r;j++) 
		{
			if (check[a[j]]) add(check[a[j]],-1);//去掉之前打的标记,避免重复
			add(j,1);
			check[a[j]]=j;
			//check[a[i]]数组用于记录a[i]在区间[1,r]中最后的位置
		}
		tmp=q[i].r+1;
		ans[q[i].id]=query(q[i].r)-query(q[i].l-1);
	}
	for (int i=1;i<=m;i++) printf("%d\n",ans[i]);
	return 0;
} 
posted @ 2019-11-05 09:44  Nanjo  阅读(113)  评论(0编辑  收藏  举报