原题地址

https://www.luogu.com.cn/problem/P2471

解题思路

准备

好像只有我维护了两棵线段树?

先定义一个 rain\textit{rain}rain 数组存放降雨量,默认值为大于降雨量最大值的数 INT\textit{INT}INT_M\textit{M}M。

一开始读入的时候对每个年份进行离散化处理,按照第一个年份对应 1\textit{1}1,得到 n\textit{n}n 个年份,对应的降雨量值存入 rain\textit{rain}rain 数组。

注意:这里 1\textit{1}1 到 n\textit{n}n 之间可能有的年份没有读入值,即不确定,它们对应的值即为 INT\textit{INT}INT_M\textit{M}M。

之后维护两棵线段树 sum\textit{sum}sum 和 realSum\textit{realSum}realSum,均是用于维护区间降雨量的最大值。

不同的是:

sum\textit{sum}sum 维护时,降雨量按照 rain\textit{rain}rain 初始处理好的值来进行,即若查询区间内存在不确定降雨量的年份,那么返回的值必定是 INT\textit{INT}INT_M\textit{M}M。

而 realSum\textit{realSum}realSum 按照真实的值来进行维护,即返回区间已确定年份的最大值。

(本质都是二分查找,就是写成线段树自己方便理解…)

讨论

那么接下来就到了激动人心的讨论环节,不得不说好多好多细节要注意…那么我们一个一个来。

分析步骤:

(以下内容与代码一致,将前面输入的年份称作 x\textit{x}x,后面的称作 y\textit{y}y,其降雨量分别为 xx\textit{xx}xx 和 yy\textit{yy}yy,年份离散化后的值为 posx\textit{posx}posx 和 posy\textit{posy}posy。)

  1. x\textit{x}x 和 y\textit{y}y 倒置/相同的话 false\textit{false}false。

  2. 若给出的年份不全在我们已知的查询区间内,即经离散化之后不在 1\textit{1}1 到 n\textit{n}n 之间,那么拿出来单独讨论。(就是这个地方调了整整两天qwq)

    这样,除了 false\textit{false}false 就是 maybe\textit{maybe}maybe,我们主要讨论 false\textit{false}false 的情况:

    • posx\textit{posx}posx 不在,posy\textit{posy}posy 在:若查询出的 realSum\textit{realSum}realSum 大于等于 yy\textit{yy}yy,为 false\textit{false}false。

    • posy\textit{posy}posy 不在,posx\textit{posx}posx 在:若查询出的 realSum\textit{realSum}realSum 大于等于 xx\textit{xx}xx,那么其后 yy\textit{yy}yy 不能同时满足大于 x\textit{x}x 到 y\textit{y}y 之间的值且不大于 xx\textit{xx}xx,故为 false\textit{false}false。

    其余情况均为 maybe\textit{maybe}maybe。

  3. 若给出的年份在我们的查询区间内,就可以用两棵线段树来查询了。

    先特判一下相邻年的情况,之后只需要讨论 true\textit{true}true 和 false\textit{false}false 即可,其余情况为 maybe\textit{maybe}maybe,个人觉得思维量会少一些些。

    • xx\textit{xx}xx 和 yy\textit{yy}yy 均已知且 xx\textit{xx}xx <=<=<= yy\textit{yy}yy,查询[ posx+1\textit{posx + 1}posx + 1,posy-1\textit{posy - 1}posy - 1 ] 得到的 sum\textit{sum}sum <<< yy\textit{yy}yy,出 true\textit{true}true。(说明区间内的值均已知,且最大值满足条件)

    • xx\textit{xx}xx 和 yy\textit{yy}yy 均已知且 xx\textit{xx}xx >>> yy\textit{yy}yy,出 false\textit{false}false。

    • yy\textit{yy}yy 已知时,若查询得到的 realSum\textit{realSum}realSum >=>=>= yy\textit{yy}yy, 出 false\textit{false}false。

    • xx\textit{xx}xx 已知时,若查询得到的 realSum\textit{realSum}realSum >=>=>= xx\textit{xx}xx, 出 false\textit{false}false。(原因和上述2的第二小点相同)

参考代码

第一次放上自己的代码,真 · 瑟瑟发抖…

#include <bits/stdc++.h>
using namespace std;
#define maxn 50010
#define ls rt << 1
#define rs rt << 1 | 1
#define M ((l + r) >> 1)
const int INT_M = 1e9 + 10;  //若有年份没有数据,降雨量的值就是这个
typedef int LL;
LL sum[maxn << 2], rain[maxn], realSum[maxn << 2];
LL n, m; void pushUp(LL rt) {sum[rt] = max(sum[ls], sum[rs]);realSum[rt] = max(realSum[ls], realSum[rs]);
}void build(LL l, LL r, LL rt) {if (l == r) {sum[rt] = rain[l];  //查询之后若区间有未知的值,返回的就是INT_M realSum[rt] = (rain[l] == INT_M ? -1 : rain[l]);  //realSum查询之后返回的是已知年份中的最大值 return;}build(l, M, ls);build(M + 1, r, rs);pushUp(rt);
}LL query(int flag, LL L, LL R, LL l, LL r, LL rt) {if (r < L || l > R) return -1;  //若区间不相交,返回一个不影响查询结果的值 if (l >= L && r <= R) return flag ? sum[rt] : realSum[rt];  //flag标记进行哪个查询 else {LL v1, v2; v1 = query(flag, L, R, l, M, ls);v2 = query(flag, L, R, M + 1, r, rs);return max(v1, v2);  //返回二者中的更大值 }
}int main() {scanf("%d", &n);  //注意这里的n不是之后建树用的n LL x, y, r, first, last;fill(rain, rain + maxn, INT_M);for (int i = 1; i <= n; i++) {scanf("%d%d", &y, &r);if (i == 1) first = y;  //记录第一年的值,年份是递增的 if (i == n) last = y;  //记录最后一年的值 rain[y - first + 1] = r;}n = last - first + 1;  //计算出(可以用线段树查询的)年份总数,用于建树 build(1, n, 1);scanf("%d", &m);LL res, realRes, xx, yy;LL posx, posy;while (m--) {res = -1;realRes = -1;scanf("%d%d", &x, &y);  //读入按照前面的年份是x,后面的是yposx = x - first + 1;  //计算出离散化之后的年份对应值 posy = y - first + 1;if (posx >= posy) {  //特判一下输入的年份倒置/相同的情况printf("false\n");continue;};res = query(1, max(1, posx + 1), min(n, posy - 1), 1, n, 1);  //max和min保证查询到(能查询的)正确的区间值realRes = query(0, max(1, posx + 1), min(n, posy - 1), 1, n, 1);//所给区间不在[1,n]内 int flag = 0;if (posx < 1 || posy > n) {if (posx < 1 && posy <= n) {if (realRes >= rain[posy]) flag = 1;} else if (posx >= 1 && posy > n) {if (realRes >= rain[posx]) flag = 1;}if (flag) printf("false\n");else printf("maybe\n");continue;}//以下为所给区间在[1,n]内 xx = rain[posx];yy = rain[posy];//特判,相邻年的情况 if (posy == posx + 1) {if (xx != INT_M && yy != INT_M) {  //若x,y均已知 if (yy > xx) printf("false\n");  //若y的降水大于x else printf("true\n");} else printf("maybe\n"); continue;}//只考虑true和false的情况 if (xx != INT_M && yy <= xx && res < yy) printf("true\n");  //若前后年份的降雨量均已知,且满足y降雨不超过x,中间的年份均严格小于y年 else if ((yy > xx && yy != INT_M) || (realRes >= yy) || (realRes >= xx) ) {  //不满足y年大于x年,中间年份均严格小于y年printf("false\n");}else printf("maybe\n");}return 0;
}

(线段树)洛谷 P2471 [SCOI2007]降雨量相关推荐

  1. 线段树 洛谷 p1531 I hate it(I hate it too)

    这里写链接内容 线段树模板 字符串是一个很诡异的问题.... #include<cstdio> #include<iostream> #include<string> ...

  2. 信息学奥赛一本通 1365:FBI树(fbi) | 1928:【04NOIP普及组】FBI树 | 洛谷 P1087 [NOIP2004 普及组] FBI 树

    [题目链接] ybt 1365:FBI树(fbi) ybt 1928:[04NOIP普及组]FBI树 洛谷 P1087 [NOIP2004 普及组] FBI 树 [题目考点] 1. 二叉树 [解题思路 ...

  3. P2471 [SCOI2007]降雨量(线段树)

    题目描述 我们常常会说这样的话:"X 年是自 Y 年以来降雨量最多的".它的含义是 X 年的降雨量不超过 Y 年,且对于任意 Y<Z<X,Z 年的降雨量严格小于 X 年 ...

  4. 二分答案——砍树(洛谷 P1873)

    题目选自洛谷P1873 分析:如果句子非常低,可以收集到的木材会更多,以至于超过需要的数量.随着砍树高度逐渐增大,获得的木材会逐渐减少.砍树高度增加到一定程度时,收集到的木材就会开始不够用.因此需要找 ...

  5. 线段树-Mex-洛谷P4137

    Mex 问题提出 有一个长度为nnn的数组{a1,a2,-,an}\{a_1,a_2,-,a_n\}{a1​,a2​,-,an​}.mmm次询问,每次询问一个区间内最小没有出现过的自然数. 题目解答 ...

  6. 洛谷 - P2472 [SCOI2007]蜥蜴(最大流)

    题目链接:点击查看 题目大意:给出一个 n * m 的迷宫,每个位置都有一个耐久度,也就是至多经过 a[ i ][ j ] 位置 ( i , j ),现在迷宫中有一些蜥蜴,每一时刻在每一个位置至多有一 ...

  7. 洛谷 P2053 [SCOI2007]修车 网络流 最小费用最大流 Dinic+Spfa

    题目链接: https://www.luogu.com.cn/problem/P2053 思路参考博客: https://www.luogu.com.cn/blog/a23333/solution-p ...

  8. [SCOI2007]降雨量 线段树和区间最值(RMQ)问题

    题目链接P2471 [SCOI2007]降雨量 听说博客观看效果更佳    这道题是比较经典的 RMQRMQRMQ 问题,找到X和Y年间的最值来进行判断真假 , 用线段树维护是比较简单好写的.然而这只 ...

  9. 信息学奥赛一本通 1107:校门外的树 | 1931:【05NOIP普及组】校门外的树 | OpenJudge NOI 1.6 06 | 洛谷 P1047 [NOIP2005 普及组] 校门外的树

    [题目链接] ybt 1107:校门外的树 ybt 1931:[05NOIP普及组]校门外的树 OpenJudge NOI 1.6 06:校门外的树 洛谷 P1047 [NOIP2005 普及组] 校 ...

最新文章

  1. 《深入理解Android:Wi-Fi,NFC和GPS》章节连载[节选]--第六章 深入理解wi-Fi Simple Configuration...
  2. Redis 深度历险:核心原理与应用实践
  3. slab 内存分配器介绍(一)
  4. (三)构建模块——Web页面建设
  5. [Story]狗尾草花园
  6. threading多线程模块
  7. struts 2读书笔记-----struts2的开发流程
  8. 一级计算机网络应用题目操作,计算机一级考试excel操作题目
  9. 看看别人家的神仙公司
  10. 无线路由器和有线路由器桥接
  11. ICCV 2015 B-CNN细粒度分类
  12. Win10系统电脑玩地平线4闪退解决方法教学
  13. Blast中文手册(2)
  14. cpu和gpu各自的作用
  15. Kali工具库之cadaver
  16. Android tcp与网络调试助手初入了解
  17. win10自带计算器闪退的解决办法
  18. 华为服务器带外如何修改,华为服务器带外地址修改器
  19. 《Springboot极简教程》继承WebMvcConfigurerAdapter: 一行代码写Controller
  20. java 微博客户端,Java新浪微博客户端开发第二步

热门文章

  1. 程序员的好代码长什么模样?
  2. 说说网页设计常用的构思方法
  3. JDK、JRE、JVM分别是什么及它们之间的有什么关联
  4. 每天5分钟玩转Kubernetes | Cluster IP底层实现
  5. 第10课:主流的分布式消息队列方案解读及比较
  6. 2022国赛中职网搭 windows组策略
  7. 一个通用中间组件,简单通用的适配 ViewPager,以及 pager 中的 RecycleView 简化复杂的操作,简单直接。
  8. 失传千年AE特效真经(五)
  9. Latex之安装GBK字体
  10. 人力资源管理计算机基础,人力资源管理-专-李佑强-计算机应用基础实践报告