Luogu P2709 小B的询问

https://www.luogu.com.cn/problem/P2709#submit

小B的询问

题目描述

小B 有一个长为 \(n\) 的整数序列 \(a\),值域为 \([1,k]\)
他一共有 \(m\) 个询问,每个询问给定一个区间 \([l,r]\),求:

\[\sum\limits_{i=1}^k c_i^2 \]

其中 \(c_i\) 表示数字 \(i\)\([l,r]\) 中的出现次数。
小B请你帮助他回答询问。

输入格式

第一行三个整数 \(n,m,k\)

第二行 \(n\) 个整数,表示 小B 的序列。

接下来的 \(m\) 行,每行两个整数 \(l,r\)

输出格式

输出 \(m\) 行,每行一个整数,对应一个询问的答案。

样例 #1

样例输入 #1

6 4 3
1 3 2 1 1 3
1 4
2 6
3 5
5 6

样例输出 #1

6
9
5
2

提示

【数据范围】
对于 \(100\%\) 的数据,\(1\le n,m,k \le 5\times 10^4\)

//标准莫队板子
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>

using namespace std;

int n, m, k, block;
int l = 1, r = 0, out[5211314], ans;
int a[5211314], pos[5211314], cnt[5211314]; 

struct ASK {
	int l, r, id;
}ask[5211314]; 

inline bool cmp(ASK a, ASK b) {
	if (pos[a.l] != pos[b.l]) return pos[a.l] < pos[b.l];
	else return a.r < b.r;
}

inline int read() {
	int x = 0, f = 1;
	char ch = getchar();
	while (ch < '0' || ch > '9') {
		if (ch == '-') f = -1;
		ch = getchar();
	}
	while (ch >= '0' && ch <= '9') {
		x = (x << 1) + (x << 3) + (ch - '0');
		ch = getchar();
	}
	return x * f;
}

inline void Add(int x) {
	ans = ans + 2 * cnt[x] * 1 + 1;
	cnt[x] ++;
	return;
}

inline void Del(int x) {
	ans = ans - 2 * cnt[x] * 1 + 1;
	cnt[x] --;
	return;
}

int main() {
	n = read();
	m = read();
	k = read();
	block = sqrt(n);
	for (int i = 1; i <= n; ++ i) {
		a[i] = read();
		pos[i] = (i - 1) / block + 1;
	}
	for (int i = 1; i <= m; ++ i) {
		ask[i].l = read();
		ask[i].r = read();
		ask[i].id = i;
	}
	sort(ask + 1, ask + 1 + m, cmp);
	for (int i = 1; i <= m; ++ i) {
		while (ask[i].l < l) Add(a[-- l]);
		while (l < ask[i].l) Del(a[l ++]);
		while (r < ask[i].r) Add(a[++ r]);
		while (ask[i].r < r) Del(a[r --]);
		out[ask[i].id] = ans;
	}
	for (int i = 1; i <= m; ++ i) {
		printf("%d\n", out[i]);
	}
	return 0;
} 
posted @ 2023-06-05 17:23  觉清风  阅读(9)  评论(0编辑  收藏  举报