/*
莫队算法:用于处理离线的区间问题
复杂度O(nsqrt(n))
1.将元素分块
2.将查询离线排序,按左区间的块编号排序,相同按右区间大小排序
3.维护一个当前的区间,根据访问的区间将左右区间扩张或收缩,整个过程与划窗很像
*/
#include <iostream>
#include <cmath>
#include <algorithm>
using namespace std;
typedef long long ll;
const int maxn = 5e4 + 5;
ll a[maxn],ans[maxn],pos[maxn],cnt[maxn];
ll res = 0; //全局变量维护答案
struct Q{
int l,r,k;
bool operator<(const Q&q)const
{
if( pos[l] == pos[q.l] ) return r < q.r;
return pos[l] < pos[q.l];
}
}q[maxn];
//询问区间的元素个数的平方和
void add(int x)
{
res -= cnt[a[x]] * cnt[a[x]];
cnt[a[x]] ++;
res += cnt[a[x]] * cnt[a[x]];
}
void sub(int x)
{
res -= cnt[a[x]] * cnt[a[x]];
cnt[a[x]] --;
res += cnt[a[x]] * cnt[a[x]];
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
int n,m,k;
cin >> n >> m >> k;
int siz = sqrt(n);
for (int i = 1; i <= n; i++)
{
cin >> a[i];
pos[i] = i / siz; //分块
}
for (int i = 1; i <= m; i++)
{
cin >> q[i].l >> q[i].r;
q[i].k = i;
}
sort(q+1,q+1+m); //排序访问
int l = 1,r = 0; //当前维护的区间
for (int i = 1; i <= m; i++) //移动区间
{
while( q[i].l < l ) add(--l);
while( q[i].r > r ) add(++r);
while( q[i].l > l ) sub(l++);
while( q[i].r < r ) sub(r--);
ans[q[i].k] = res;
}
for (int i = 1; i <= m; i++)
{
cout << ans[i] << '\n';
}
return 0;
}
莫队算法
最新推荐文章于 2023-04-10 22:44:02 发布