题目链接
题目分析
题意:有个人在学泡咖啡,因此看了很多关于泡咖啡温度的书,得到了n种推荐的泡咖啡温度范围[L1,R1] ,此人将有k种做法推荐的温度记为可用温度(个人翻译),然后给出q次询问,问区间[L2,R2]内的温度,有多少个温度是可用温度(每个整数代表一个温度)
思路:一开始用的是线段树写的,不过姿势不对,TLE了,然后改过来后,发现时间比较长,就考虑一下优化的方法。
比线段树某些功能更优的算法:差分思想,在对某一区间每个位置上的数加上一个值x,并求任意位置的数的时候,时间上比线段树 O(nlogn)的复杂度更低,为O(n),空间更小,代码更短,很合适。
那么如何运用差分思想来写这个题呢?首先用O(n)的时间求出每个温度有多少种做法推荐,然后维护一个前缀和sum[i],记录区间 [1, i ] 表示的温度中有多少个温度满足条件(即有多少个温度有k种以上做法推荐),用O(n)的时间求出sum数组,sum[i] = sum[i-1] + (val[i] >= k ? 1 : 0;) ,最后查询区间[ L2,R2]有多少适合的温度时,输出 sum[R2] - sum[L2-1] 。
(不了解什么是差分的话,可以看下我的这篇博客 差分+树上差分)
代码区
#include<iostream> #include<cstdio> #include<algorithm> #include<cstring> #include<queue> #include<string> #include<fstream> #include<vector> #include<stack> #include <map> #include <iomanip> #define bug cout << "**********" << endl #define show(x,y) cout<<"["<<x<<","<<y<<"] " //#define LOCAL = 1; using namespace std; typedef long long ll; const int inf = 0x3f3f3f3f; const ll mod = 1e9 + 7; const int Max = 2e5 + 10; int n, k, q; int val[Max], sum[Max]; //val为差分数组,sum[i]记录区间[1,i]有多少个温度被确定为合适 int main() { #ifdef LOCAL freopen("input.txt", "r", stdin); freopen("output.txt", "w", stdout); #endif while (scanf("%d%d%d", &n, &k, &q) != EOF) { memset(val, 0, sizeof(val)); memset(sum, 0, sizeof(sum)); for (int i = 1, l, r; i <= n;i++) { scanf("%d%d", &l, &r); val[l]++;val[r + 1]--; } for (int i = 1;i <= 200000 ;i++) { val[i] += val[i - 1]; //差分数组的前缀和即为该点的值 sum[i] = sum[i-1] + (val[i] >= k ? 1 : 0); } for(int i = 1 ,l,r;i <= q; i ++) { scanf("%d%d", &l, &r); printf("%d ", sum[r] - sum[l-1]); } } return 0; }