【HZNU Summer training】CF-816B Karen and Coffee(一维前缀和、差分)

    (配图一度让我精神恍惚)

    此题此意是,Karen要煮咖啡,但想要知道合适的温度。给出n个温度区间,再给出一个常数k,并做q次询问。如果某个温度在所有区间中出现次数不小于k,就是一个合适的温度。要求输出每次询问的温度区间中有多少合适的温度。

    数据的规模导致了这题必定不能暴力。查询次数可能很大,而且区间范围也不小,因此我们需要低时间复杂度的处理和查询。那么就可以使用前缀和和差分。

    何为前缀和?可以理解成一个数列的前n项和。差分可以快速维护一个区间的加减操作,如何维护?假如我要使a[i]到a[i+j]区间都加2,那么我就使a[i]+=2,a[i+j-1]-=2,在查询前用前缀和滚一遍数组,就可以完成所有区间修改,并能用a[i+j]-a[i-1]来查询区间和。有兴趣的同学可以在草稿纸上演算一次。

    那么这一题如何分析?先看代码:

#include<iostream>
#include<cmath>
#include<set>
#include<map>
#include<algorithm>
#include<queue>
#include<cstring>
#include<string>
#include<vector>
#include<cstdio>
#define INF 0x3f3f3f3f
using namespace std;
int n,k,q;
int a[200005],sum[200005];
void Input() {
	memset(a,0,sizeof(a));
	memset(sum,0,sizeof(sum));
	cin>>n>>k>>q;
	for(int i=0; i<n; i++) {
		int x,y;
		cin>>x>>y;
		a[x]++;
		a[y+1]--;
	}
}
void Update() {
	for(int i=1; i<200005; i++) {
		a[i]+=a[i-1];
		if(a[i]>=k) {
			sum[i]=1;
		}
	}
	for(int i=1; i<200005; i++) {
		sum[i]+=sum[i-1];
	}
}
void Query(){
	int A,B;
	for(int i=0;i<q;i++){
		cin>>A>>B;
		cout<<sum[B]-sum[A-1]<<endl;
	}
}
int main() {
	Input();
	Update();
	Query();
	return 0;
}

    既然要求区间中合法数字的个数,那么我需要先确定哪些是合法数字。首先用a数组来表示所有的温度,用sum数组的01值标出合法温度,在输入区间时做差分,输入完毕后滚一次前缀和来更新数组,更新的同时与常数k比较,如果不小于k,就可以把它在sum数组里表示为1。最后把sum数组滚一遍前缀和,这时候sum数组里的数据就更新为小于当前温度的合法温度个数和,此时就可以用O(1)的操作来查询区间。

猜你喜欢

转载自blog.csdn.net/linyiduo123/article/details/81204340
今日推荐