【牛客小白月赛17】G

题目大意:

题目链接:https://ac.nowcoder.com/acm/contest/1085/G
小sun最近突然对区间来了兴趣,现在他有这样一个问题想问问你:
给你n个数,每个数为aia_i ,现在有mm个询问,每个询问l,rl,r,需要求出:
i=lrai×num(ai)sum^{r}_{i=l}a_i imes num(a_i)
其中num(ai)num(a_i)代表aia_i在这个区间中出现的次数。
你能帮帮他吗?


思路:

对于区间[l,r][l,r]的每一个数字xx,一共有num(x)num(x)xx,每一个xx的贡献是x×num(x)x imes num(x)。所以数字xx的贡献是x×num(x)2x imes num(x)^2
题目中保证了1n,m,ai1051leq n,m,a_ileq 10^5,而且没有强制在线,明显就是一道莫队的板子题了。
而且这道题和小Z的袜子还很像,改一下就可以了。


代码:

#include <cmath>
#include <cstdio>
#include <algorithm>
using namespace std;
typedef long long ll;

const int N=100010;
int n,m,T,l,r,a[N],pos[N];
ll ans[N],sum,s[N];

struct Ask
{
	int l,r,id;
}ask[N];

bool cmp(Ask x,Ask y)
{
	if (pos[x.l]<pos[y.l]) return 1;
	if (pos[x.l]>pos[y.l]) return 0;
	return x.r<y.r;
}

void add(int x) 
{
	sum-=s[a[x]]*s[a[x]]*a[x];
	s[a[x]]++;
	sum+=s[a[x]]*s[a[x]]*a[x];
}

void dev(int x)
{
	sum-=s[a[x]]*s[a[x]]*a[x];
	s[a[x]]--;
	sum+=s[a[x]]*s[a[x]]*a[x];
}

int main()
{
	scanf("%d%d",&n,&m);
	T=(int)sqrt(m);
	if (m%T) T++;
	for (int i=1;i<=n;i++)
		scanf("%d",&a[i]);
	for (int i=1;i<=m;i++)
	{
		scanf("%d%d",&ask[i].l,&ask[i].r);
		ask[i].id=i;
		pos[i]=(i-1)/T+1;
	}
	sort(ask+1,ask+1+m,cmp);
	l=1;
	for (int i=1;i<=m;i++)
	{
		for (;l<ask[i].l;l++) dev(l);
		for (;l>ask[i].l;l--) add(l-1);
		for (;r<ask[i].r;r++) add(r+1);
		for (;r>ask[i].r;r--) dev(r);
		ans[ask[i].id]=sum;
	}
	for (int i=1;i<=m;i++)
		printf("%lld
",ans[i]);
	return 0;
}

原文地址:https://www.cnblogs.com/hello-tomorrow/p/11998029.html