P2709 小B的询问(普通莫队)

题目

传松门
题目描述
小B有一个序列,包含N个1~K之间的整数。他一共有M个询问,每个询问给定一个区间[L…R],求Sigma(c(i)^2)的值,其中i的值从1到K,其中c(i)表示数字i在[L…R]中的重复次数。小B请你帮助他回答询问。
输入输出格式
输入格式:
第一行,三个整数N、M、K。
第二行,N个整数,表示小B的序列。
接下来的M行,每行两个整数L、R。
输出格式:
M行,每行一个整数,其中第i行的整数表示第i个询问的答案。

题解

  • 莫队板子题
  • 修改时
inline void add(int x) {
	cnt[ a[x] ]++; 
	ans += cnt[ a[x] ] * 2 - 1; 
}

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

上面修改自己手推一下应该就可以了,其实就是完全平方公式

code

#include <bits/stdc++.h> 
using namespace std; 
const int maxn = 5e4 + 1000; 

template <typename T>
inline void read(T &s) {
	s = 0; 
	T w = 1, ch = getchar(); 
	while (!isdigit(ch)) { if (ch == '-') w = -1; ch = getchar(); }
	while (isdigit(ch)) { s =  (s << 1) + (s << 3) + (ch ^ 48); ch = getchar(); }
	s *= w; 
}

int n, m, k, ans; 
int a[maxn], pos[maxn], res[maxn], cnt[maxn]; 
struct query { int l, r, id; } q[maxn]; 

inline bool cmp(query A, query B) {
	return (pos[A.l] == pos[B.l]) ? A.r < B.r : A.l < B.l; 
}

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

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

int main() {
	read(n), read(m), read(k);  
	int blo = n / sqrt(m); 
	for (int i = 1; i <= n; ++i) {
		read(a[i]); 
		pos[i] = (i - 1) / blo + 1; 
	}
	for (int i = 1; i <= m; ++i) {
		read(q[i].l), read(q[i].r); 
		q[i].id = i; 
	}
	sort(q + 1, q + m + 1, cmp); 
	
	int l = 1, r = 0; 
	for (int i = 1; i <= m; ++i) {
		int ql = q[i].l, qr = q[i].r; 
		while (l < ql) del(l++); 
		while (l > ql) add(--l); 
		while (r < qr) add(++r); 
		while (r > qr) del(r--); 
		res[ q[i].id ] = ans; 
	}
	
	for (int i = 1; i <= m; ++i)
		printf("%d\n", res[i]); 
	return 0; 
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值