莫队

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;
}
posted @ 2026-04-14 01:04  kzssCCC  阅读(5)  评论(0)    收藏  举报