CF86D 题解
看起来线段树之类的不好维护,但是移动区间的增量很好求,数据范围也能过,那么直接莫队就行了。
设加入或删除了值 \(x\),设原来区间内有 \(cnt_x\) 个,现在有 \(cnt'_x\) 个,那么增量就是 \(x((cnt'_x)^2-(cnt_x)^2)\),直接求就好了。
复杂度 \(O(t\sqrt n)\)。
#include<bits/stdc++.h>
using namespace std;
using ll = long long;
const int N = 2e5 + 5, M = 1e6 + 5;
int n, m, sqn;
int cnt[M], a[N], blk[N];
ll answ[N];
struct node{int l, r, id;}q[N];
inline ll add(int x, int v)
{
ll now = 1ll * cnt[x] * cnt[x] * x;
cnt[x] += v;
ll now2 = 1ll * cnt[x] * cnt[x] * x;
return now2 - now;
}
int main()
{
ios::sync_with_stdio(0);cin.tie(0);
cin >> n >> m;
sqn = pow(n, 0.6);
for(int i = 1; i <= n; i ++)
cin >> a[i], blk[i] = i / sqn;
for(int i = 1; i <= m; i ++)
{
int x, y;
cin >> x >> y;
q[i].l = x, q[i].r = y, q[i].id = i;
}
sort(q + 1, q + m + 1, [](node x, node y){
if(blk[x.l] == blk[y.l]) return x.r < y.r;
return blk[x.l] < blk[y.l];
});
int l = 1, r = 0, t = 0; ll ans = 0;
for(int i = 1; i <= m; i ++)
{
while(r < q[i].r) r ++, ans += add(a[r], 1);
while(l > q[i].l) l --, ans += add(a[l], 1);
while(r > q[i].r) ans += add(a[r], -1), r --;
while(l < q[i].l) ans += add(a[l], -1), l ++;
answ[q[i].id] = ans;
}
for(int i = 1; i <= m; i ++)
cout << answ[i] << "\n";
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】