题解 P4113【HEOi2012】采花

分析

考虑对每一种花,它在区间内能做贡献当且仅当区间内有两朵以上该种类的花,所以我们对每一个右端点,使它左侧每一种花的倒数第二个位置做贡献,这样能保证贡献被统计正确,避免选漏,然后就转化为前缀问题,用树状数组 \(logn\) 即可解决,然后将询问按右端点排序,每次右移时将它前面同类型的贡献加一,前面的前面减一,避免算重,计算区间贡献和即可。

Code


#include<bits/stdc++.h>
using namespace std;
inline void read(int &res){
	char c;
	int f=1;
	res=0;
	c=getchar();
	while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
	while(c>='0'&&c<='9')res=(res<<1)+(res<<3)+c-48,c=getchar();
	res*=f;
}
int n,c,m;
int pos[2000005],a[2000005],fr[2000005];
struct node{
	int l,r,id;
}q[2000005];
inline bool cmp(node aa,node bb){return aa.r<bb.r;}
int t[2000005];
inline int lowbit(int x){return -x&x;}
inline void update(int x,int y){
	if(!x)return;
	for(int i=x;i<=n;i+=lowbit(i))t[i]+=y;
}
inline int query(int x){
	int sum=0;
	for(int i=x;i;i-=lowbit(i))sum+=t[i];
	return sum;
}
int ans[2000005];
int main()
{
	read(n);read(c);read(m);
	for(int i=1;i<=n;i++){
		read(a[i]);
		if(pos[a[i]]){
			fr[i]=pos[a[i]];
		}
		pos[a[i]]=i;
	}
	for(int i=1;i<=m;i++){
		read(q[i].l);read(q[i].r);
		q[i].id=i;
	}
	sort(q+1,q+m+1,cmp);
	int r=0;
	for(int i=1;i<=m;i++){
		while(r<q[i].r){
			r++;
			update(fr[r],1);
			update(fr[fr[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;
}

上一篇:C语言 getchar()原理及易错点解析


下一篇:[考试总结]ZROI-21-NOIP冲刺-TEST17 总结