CF433B Kuriyama Mirai's Stones 题解

Content

有一个长度为 \(n\) 的数组 \(a_1,a_2,a_3,...,a_n\)。有 \(m\) 次询问,询问有以下两种:

  • \(1~l~r\),求 \(\sum\limits_{i=l}^ra_i\)
  • \(2~l~r\),将数组非降序排列后再依次标号,然后再求 \(\sum\limits_{i=l}^ra_i\)

数据范围:\(1\leqslant l\leqslant r\leqslant n\leqslant 10^5,1\leqslant m\leqslant 10^5,1\leqslant a_i\leqslant 10^9\)

Solution

这道题旨在考察对前缀和的操作,比如说这道题目我们就可以用前缀和很好地求解。具体如下:

我们先将没有排序的数组求出他们的前缀和 \(s_i=\sum\limits_{j=1}^ia_j\),然后再按照题目要求排序得到 \(a'\) 数组,再求出 \(s'_i=\sum\limits_{j=1}^ia_j\)。再接着,我们根据两种不同的操作分类讨论:

  1. 对于第一种操作,我们知道:\(s_{l-1}=\sum\limits_{i=1}^{l-1} a_i,s_r=\sum\limits_{i=1}^n a_i\)。由此我们得到 \(s_r-s_{l-1}=a_r+a_{r-1}+...+a_l+a_{l-1}+...+a_1-(a_l+a_{l-1}+...+a_l)=a_l+a_{l+1}+...+a_r\)。正好就是我们所要求的 \([l,r]\) 这个区间内所有数的总和。由此我们就知道了,第一种操作的答案就是 \(s_r-s_{l-1}\)
  2. 对于第二种操作,和第一种操作类似,只不过变成了排序后的数组的前缀和罢了,除了排序以外几乎没什么差别,答案就是 \(s'_r-s'_{l-1}\)

Code

#include <cstdio>
#include <cstring>
#include <cmath>
#include <iostream>
#include <algorithm>
using namespace std;

int n, m, a1[100007], a2[100007];
long long sum[3][100007];

int main() {
	scanf("%d", &n);
	for(int i = 1; i <= n; ++i) {
		scanf("%d", &a1[i]);
		a2[i] = a1[i];
	}
	sort(a2 + 1, a2 + n + 1);
	for(int i = 1; i <= n; ++i)
		sum[1][i] = sum[1][i - 1] + a1[i], sum[2][i] = sum[2][i - 1] + a2[i];
	scanf("%d", &m);
	while(m--) {
		int opt, l, r;
		scanf("%d%d%d", &opt, &l, &r);
		printf("%lld\n", sum[opt][r] - sum[opt][l - 1]);
	}
	return 0;
}
posted @ 2021-12-17 14:17  Eason_AC  阅读(18)  评论(0)    收藏  举报