BZOJ3781&&洛谷P2709 小B的询问

莫队裸题,不讲

主要是我们如何得到结果

我们发现假如在上一个区间内a出现了b次,那么那么显然在这个区间内的初始ans=b^2,然后假如我们又找到了一个a,那么ans=(b+1)^2=b^2+2b+1,所以我们就可以转移了,但是因为我们是先找到的次数,所以,我们+2*b的时候实际上加的是2*(b+1)+1,也就是说我们还需要-1,所以转移变成了ans+=(2*cnt[b]-1)

代码

#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define inl inline
#define lli long long int
using namespace std;
const int M=50005;
struct que{int l,r,id;lli ans;}e[M];
int n,m,q,block;
int b[M],bloc[M];
lli cnt[M],em[M];
inl int read()
{
	int x=0;char ch=getchar();
	while (ch>'9'||ch<'0') ch=getchar();
	while (ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
	return x;
}
inl bool cmp1(que a,que b)
{
	if (bloc[a.l]==bloc[b.l]) return a.r<b.r;
	return a.l<b.l;
}
inl bool cmp2(que a,que b){return a.id<b.id;}
inl void slove()
{
	int l=1,r=0;lli ans=0;
	for (int i=1;i<=m;i++)
	{
		for (;l>e[i].l;) cnt[b[--l]]++,ans+=(2*cnt[b[l]]-1);
		for (;r<e[i].r;) cnt[b[++r]]++,ans+=(2*cnt[b[r]]-1);
		for (;l<e[i].l;l++) cnt[b[l]]--,ans-=(2*cnt[b[l]]+1);
		for (;r>e[i].r;r--) cnt[b[r]]--,ans-=(2*cnt[b[r]]+1);
		e[i].ans=ans;
	}
	return ;
}
int main()
{
	n=read();m=read();q=read();block=sqrt(n);
	for (int i=1;i<=n;i++) b[i]=read();
	for (int i=1;i<=n;i++) 
		bloc[i]=(i-1)/block+1;
	for (int i=1;i<=m;i++)
		e[i].l=read(),e[i].r=read(),e[i].id=i;
	sort(e+1,e+m+1,cmp1);
	slove();
	sort(e+1,e+m+1,cmp2);
	for (int i=1;i<=m;i++)
		printf("%lld\n",e[i].ans);
	return 0;
}


猜你喜欢

转载自blog.csdn.net/acerandaker/article/details/81036654
今日推荐