BZOJ-1067 降雨量 线段树+分类讨论
来源:互联网 发布:海信网络电视多吗 编辑:程序博客网 时间:2024/05/21 17:52
这道B题,刚的不行,各种碎点及其容易忽略,受不鸟了直接
1067: [SCOI2007]降雨量
Time Limit: 1 Sec Memory Limit: 162 MB
Submit: 2859 Solved: 735
[Submit][Status][Discuss]
Description
我们常常会说这样的话:“X年是自Y年以来降雨量最多的”。它的含义是X年的降雨量不超过Y年,且对于任意Y<Z<X,Z年的降雨量严格小于X年。例如2002,2003,2004和2005年的降雨量分别为4920,5901,2832和3890,则可以说“2005年是自2003年以来最多的”,但不能说“2005年是自2002年以来最多的”由于有些年份的降雨量未知,有的说法是可能正确也可以不正确的。
Input
输入仅一行包含一个正整数n,为已知的数据。以下n行每行两个整数yi和ri,为年份和降雨量,按照年份从小到大排列,即yi<yi+1。下一行包含一个正整数m,为询问的次数。以下m行每行包含两个数Y和X,即询问“X年是自Y年以来降雨量最多的。”这句话是必真、必假还是“有可能”。
Output
对于每一个询问,输出true,false或者maybe。
Sample Input
6
2002 4920
2003 5901
2004 2832
2005 3890
2007 5609
2008 3024
5
2002 2005
2003 2005
2002 2007
2003 2007
2005 2008
Sample Output
false
true
false
maybe
false
HINT
100%的数据满足:1<=n<=50000, 1<=m<=10000, -10^9<=yi<=10^9, 1<=ri<=10^9
Source
POJ 2637 WorstWeather Ever
这道题,理性的来分析一下(遇到这种题,和我谈理性??)先给出一些年份的信息,然后给出一些年份对,求解不难想到线段树来维护一下区间最值(其实ST表编起来快多了)由数据看出需要离散,当然输入人性化排序给出,所以不是很难,只需要开个struct数组来保存各个年份区间,建树相对繁琐...然后分类讨论下结果:先设两个端点年份为X,Y;题目需要满足r【x】<=r【y】,且任意X<Z<Y都满足,r【Z】<【Y】;TRUE:两个端点数值已知,且左端点数值小于等于右端点数值,两端点间各年份都已知,且数值都小于右端点数值MAYBE:1.两个端点数值都已知,且左端点数值小于等于右端点数值,中间有未知年份,且已知年份数值皆小于右端点数值2.左端点有值,右端点无值,中间端点随意了3.左端点无值,右端点无值,中间端点更随意4.左端点无值,右端点有值,中间端点允许有未知年份,但已知年份数值小于右端点数值5.右端点为已知端点的第一个or左端点为已知端点的最后一个FALSE:不是false的都讨论完了,剩下的只能是false了,不满足上述种种的直接false掉!说起来,第一次写需要struct存储和操作的线段树,写起来确实不是很习惯QAQ.....感谢友善的黄学长在我迷茫时给我的交谈,开导ORZ
下面是代码:
#include<iostream>#include<cstdio>#include<algorithm>#include<cstring>using namespace std;#define maxn 50010struct data{ int l,r,maxr; bool know;};data rain[maxn<<2];void updataknow(int now){ rain[now].know=rain[now<<1].know && rain[now<<1|1].know; }//向上更新区间各年份是否都存在这一信息 void updatamaxr(int now){ rain[now].maxr=max(rain[now<<1].maxr,rain[now<<1|1].maxr);}//更新区间最大降雨量 void build(int now,int l,int r){ if (l==r) { int x,y; scanf("%d%d",&x,&y); rain[now].l=rain[now].r=x; rain[now].maxr=y; rain[now].know=true; return; }//添加点的值 int mid=(l+r)>>1; build(now<<1,l,mid); build(now<<1|1,mid+1,r); updataknow(now); if (rain[now<<1].r+1!=rain[now<<1|1].l)//如果两个区间相结合,若左子区间的最后年份+1不等于右子区间的最先年份,则根区间不全 rain[now].know=false; rain[now].l=rain[now<<1].l;rain[now].r=rain[now<<1|1].r;//更新跟区间的最早最晚年份 updatamaxr(now);}//建树 int getpoint(int now,int loc){ if (rain[now].l==rain[now].r) if (rain[now].l!=loc) return 0; else return rain[now].maxr; if (loc<=rain[now<<1].r) return getpoint(now<<1,loc); else if (loc>=rain[now<<1|1].l) return getpoint(now<<1|1,loc); return 0;}//获取点的值 ,如果此点不存在返回0 int askquery(int L,int R,int now,int data)//返回值为1表示端点不是最大,2表示都已知且都小于端点,3表示存在未知但已知的都小于端点 { bool f=false;//判断询问是否超界(这道题中,易望点1) if (L<rain[now].l) { L=rain[now].l; f=true; }//先判断查询区间是否超过 最大区间 if (L==rain[now].l && R==rain[now].r) { if (rain[now].maxr>=data) return 1;//如果区间最大值比端点数值大,就返回1 else if (rain[now].know==true && f==false) return 2;//如果全都已知且不超界且小于端点返回2 else return 3;//有未知的东东或者超界了但已知的都大于端点就返回3 } if (R<=rain[now<<1].r) return askquery(L,R,now<<1,data);//如果询问区间全都在左子区间返回与左子区间的关系 else if (L>=rain[now<<1|1].l) return askquery(L,R,now<<1|1,data);//同上讨论与右子区间关系 else { int x=askquery(L,rain[now<<1].r,now<<1,data); int y=askquery(rain[now<<1|1].l,R,now<<1|1,data); if (x==1 || y==1) return 1;//有一半比端点要大,就返回1 else if (rain[now<<1].r+1!=rain[now<<1|1].l) return 3;//左子区间的最大年份+1若不等于右子区间最小年份返回3 else return 2;//其余返回2 }//查询区间在两个子区间之间 }//查询此区间与数值的关系 int former(int now,int loc){ if (rain[now].l==rain[now].r) return rain[now].l; else if (loc>rain[now<<1|1].l) return former(now<<1|1,loc); else return former(now<<1,loc);}//求loc的前一个存在具体值的年份(可以为本身) int latter(int now,int loc){ if (rain[now].l==rain[now].r) return rain[now].l; else if (loc<rain[now<<1].r) return latter(now<<1,loc); else return latter(now<<1|1,loc);}//求loc的后一个存在具体值的年份(亦可以为本身) int main(){ int n,m; scanf("%d",&n); build(1,1,n); scanf("%d",&m); for (int i=1; i<=m; i++) { int x,y; scanf("%d%d",&x,&y); int a=getpoint(1,x),b=getpoint(1,y);//a表示查询区间左端点的值,b表示右端点的值 if (a==0 && b==0) puts("maybe");//a和b都未知==>maybe else { int left=latter(1,x),right=former(1,y);//left表示左端点后面有值的第一个点,right则是右端点前面有值的第一个点 if (a==0)//假使只有左端点未知 { if (left>right || y==right) {puts("maybe");continue;} if (askquery(left,right,1,b)==1) puts("false");//left和right之间值比右端点值大==>false else puts("maybe"); } else if (b==0)//假使只有右端点未知 { if (left>right || x==left) {puts("maybe");continue;} if (askquery(left,right,1,a)==1) puts("false");//同上述 else puts("maybe"); } else//左右端都已知 { if (b>a) {puts("false");continue;}//左端值小于右端值==>false if (left>right) if (x+1==y) {puts("true");continue;} else {puts("maybe");continue;} if (askquery(left,right,1,b)==1) {puts("false");continue;} else if (askquery(left,right,1,b)==2) if (left==x+1 && right==y-1) {puts("true");continue;} else {puts("maybe");continue;} else if (askquery(left,right,1,b)==3) puts("maybe"); else {puts("false");continue;} } } } return 0;}
- BZOJ-1067 降雨量 线段树+分类讨论
- 【bzoj1067】【SCOI2007】【降雨量】【线段树+分类讨论】
- BZOJ 1067 降雨量 线段树
- bzoj 1067 降雨量 线段树
- BZOJ 1067: [SCOI2007]降雨量 二分,RM0Q预处理,分类讨论
- 【SCOI2007】【BZOJ1067】【codevs2439】降雨量,分类讨论の线段树
- BZOJ 1067 [SCOI2007]降雨量 线段树
- 【BZOJ 1067】[SCOI2007]降雨量 线段树
- BZOJ 1067 降雨量 (线段树)
- bzoj 1067: [SCOI2007]降雨量 RMQ+讨论
- 【BZOJ1067】【POJ2637】WorstWeather Ever【SCOI2007】降雨量 线段树+恶心讨论
- 【BZOJ 1067】 [SCOI2007]降雨量
- bzoj 1067: [SCOI2007]降雨量
- bzoj 1067 [SCOI2007]降雨量
- bzoj 1067: [SCOI2007]降雨量
- [bzoj] 1067: [SCOI2007]降雨量
- BZOJ 1067: [SCOI2007]降雨量
- BZOJ 1067 [SCOI2007]降雨量 RMQ
- Java 数组
- 常用的正则表达式
- 【HDU1166】敌兵布阵,线段树练习
- 端口映射,在内网映射外网,利用P2P实现外面跨网穿透nat访问内网80网站和应用
- io流操作之对象流代码
- BZOJ-1067 降雨量 线段树+分类讨论
- jqeru中ui拖动插件怎么获取被拖动对象的id
- [转]傅立叶变换与小波分析的关系
- io流操作之数据流代码
- poj_1833
- C语言
- jascript中常见的几个兼容问题
- Combine Two Tables
- MySQL 存储过程那点事儿