莫队
https://www.luogu.com.cn/problem/P2709
题意概述:求区间中 $[1,k]$ 出现次数平方的总和
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
using ull = unsigned long long;
int n,m,k;
vector<int> arr(n+1);
class Q{
public:
int l,r,id;
ll ans;
};
vector<Q> q_arr;
void solve(){
cin >> n >> m >> k;
//块长
int block = sqrt(n);
arr = vector<int>(n+1);
for (int i=1;i<=n;i++){
cin >> arr[i];
}
//离线
q_arr = vector<Q>(m+1);
for (int i=1;i<=m;i++){
cin >> q_arr[i].l >> q_arr[i].r;
q_arr[i].id = i;
}
//排序
sort(q_arr.begin()+1,q_arr.end(),[&](Q& q1,Q& q2){
if (q1.l/block != q2.l/block) return q1.l/block < q2.l/block;
//优化:奇数降序,偶数升序
return q1.l/block&1?q1.r>q2.r:q1.r<q2.r;
});
vector<int> cnt(k+1,0);
int l = 1;
int r = 0;
ll ans = 0;
for (int i=1;i<=m;i++){
int cl = q_arr[i].l;
int cr = q_arr[i].r;
//注意每个分支指针移动的顺序
while (r<cr){
r++;
ans += (ll)cnt[arr[r]]*2+1;
cnt[arr[r]]++;
}
while (r>cr){
ans -= (ll)cnt[arr[r]]*2-1;
cnt[arr[r]]--;
r--;
}
while (l>cl){
l--;
ans += (ll)cnt[arr[l]]*2+1;
cnt[arr[l]]++;
}
while (l<cl){
ans -= (ll)cnt[arr[l]]*2-1;
cnt[arr[l]]--;
l++;
}
q_arr[i].ans = ans;
}
//重新以id排序输出
sort(q_arr.begin()+1,q_arr.end(),[&](Q& p1,Q& p2){
return p1.id < p2.id;
});
for (int i=1;i<=m;i++){
cout << q_arr[i].ans << '\n';
}
}
int main(){
ios::sync_with_stdio(false);
cin.tie(0);
solve();
return 0;
}

浙公网安备 33010602011771号