#洛谷 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个询问的答案。

输入输出样例

输入 #1复制

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

输出 #1复制

6
9
5
2

说明/提示

对于全部的数据,1<=N、M、K<=50000

题目大意 : 输入长度为 N 的序列, 有M 次查询,  每次查询某个区间内, 输出所有数的出现次数的平方和

思路 : 很明显是个莫队, 每次更新之前, 减去上一次的值, 再加上当前的值, 离线保存即可

Accepted code

#include<bits/stdc++.h>
#include<unordered_map>
using namespace std;

#define sc scanf
#define ls rt << 1
#define rs ls | 1
#define Min(x, y) x = min(x, y)
#define Max(x, y) x = max(x, y)
#define ALL(x) (x).begin(),(x).end()
#define SZ(x) ((int)(x).size())
#define MEM(x, b) memset(x, b, sizeof(x))
#define lowbit(x) ((x) & -(x))
#define P2(x) ((x) * (x))

typedef long long ll;
const int MOD = 1e9 + 7;
const int MAXN = 1e5 + 100;
const int INF = 0x3f3f3f3f;
inline ll fpow(ll a, ll b){ ll r = 1, t = a; while (b){ if (b & 1)r = (r*t) % MOD; b >>= 1; t = (t*t) % MOD; }return r; }

struct node
{
	int l, r, x;
}e[MAXN];
int p[MAXN], belong[MAXN], n, m, k;
int num[MAXN], sz, sum, L = 1, R; 
ll pre[MAXN], ans; 
bool cmp(node a, node b) {
	if (belong[a.l] == belong[b.l]) return a.r < b.r;
	return belong[a.l] < belong[b.l];
}
void add(int x) {
	ans -= P2(num[p[x]]);
	num[p[x]]++; ans += P2(num[p[x]]);
}
void del(int x) {
	ans -= P2(num[p[x]]);
	num[p[x]]--; ans += P2(num[p[x]]);
}

int main()
{
	cin >> n >> m >> k; sz = sqrt(n);
	sum = ((double)n / sz);
	for (int i = 1; i <= sz; i++) {
		for (int j = (i - 1) * sum; j <= i * sum; j++)
			belong[j] = i;
	}
	for (int i = 1; i <= n; i++) sc("%d", &p[i]);
	for (int i = 1; i <= m; i++) sc("%d %d", &e[i].l, &e[i].r), e[i].x = i;
	sort(e + 1, e + m + 1, cmp);
	for (int i = 1; i <= m; i++) {
		int l = e[i].l, r = e[i].r, id = e[i].x;
		while (L < l) del(L++);
		while (L > l) add(--L);
		while (R > r) del(R--);
		while (R < r) add(++R);
		pre[id] = ans;
	}
	for (int i = 1; i <= m; i++) printf("%lld\n", pre[i]);
	return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值