bzoj 2743: [HEOI2012]采花【树状数组】

离线,按照l排序
注意到在区间里出现两次的颜色才有贡献,所以记录一个ne[i]表示i后第一个和i同色的花,维护一个l,每次处理询问的时候l单调右移,树状数组维护,在ne[ne[i]]位置++,在ne[i]位置--(因为这里已经++过了),这样区间查询的时候如果右端点超过ne[ne[i]]就能对答案有贡献
注意在开始的时候给有ne的第一次出现的颜色的位置++

#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
const int N=2000006;
int n,c,m,a[N],ne[N],ans[N],t[N],p[N];
struct qwe
{
	int l,r,id;
}q[N];
bool cmp(const qwe &a,const qwe &b)
{
	return a.l<b.l;
}
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 v)
{
	for(int i=x;i<=n;i+=(i&(-i)))
		t[i]+=v;
}
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(),c=read(),m=read();
	for(int i=1;i<=n;i++)
		a[i]=read();
	for(int i=n;i>=1;i--)
		ne[i]=p[a[i]],p[a[i]]=i;
	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);
	for(int i=1;i<=c;i++)
		if(p[i]&&ne[p[i]])
			update(ne[p[i]],1);
	for(int i=1,l=1;i<=m;i++)
	{
		for(;l<q[i].l;l++)
		{
			if(ne[l])
				update(ne[l],-1);
			if(ne[ne[l]])
				update(ne[ne[l]],1);
		}
		ans[q[i].id]=ques(q[i].r)-ques(q[i].l-1);
	}
	for(int i=1;i<=m;i++)
		printf("%d
",ans[i]);
	return 0;
}
原文地址:https://www.cnblogs.com/lokiii/p/9602603.html