题目大意:
题目链接:https://ac.nowcoder.com/acm/contest/1085/G
小sun最近突然对区间来了兴趣,现在他有这样一个问题想问问你:
给你n个数,每个数为
a
i
a_i
ai ,现在有
m
m
m个询问,每个询问
l
,
r
l,r
l,r,需要求出:
∑
i
=
l
r
a
i
×
n
u
m
(
a
i
)
\sum^{r}_{i=l}a_i\times num(a_i)
∑i=lrai×num(ai)
其中
n
u
m
(
a
i
)
num(a_i)
num(ai)代表
a
i
a_i
ai在这个区间中出现的次数。
你能帮帮他吗?
思路:
对于区间
[
l
,
r
]
[l,r]
[l,r]的每一个数字
x
x
x,一共有
n
u
m
(
x
)
num(x)
num(x)个
x
x
x,每一个
x
x
x的贡献是
x
×
n
u
m
(
x
)
x\times num(x)
x×num(x)。所以数字
x
x
x的贡献是
x
×
n
u
m
(
x
)
2
x\times num(x)^2
x×num(x)2。
题目中保证了
1
≤
n
,
m
,
a
i
≤
1
0
5
1\leq n,m,a_i\leq 10^5
1≤n,m,ai≤105,而且没有强制在线,明显就是一道莫队的板子题了。
而且这道题和小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\n",ans[i]);
return 0;
}
本文介绍了一种使用莫队算法解决复杂区间查询问题的方法。通过实例解析,阐述了如何处理大规模数据集上的区间查询,特别是在涉及大量询问的情况下。文章详细解释了算法的实现过程,包括关键的数据结构和算法优化技巧。
1185

被折叠的 条评论
为什么被折叠?



