「BZOJ1067」[SCOI2007] 降雨量
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
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
true
false
maybe
false
HINT
100%的数据满足:1<=n<=50000, 1<=m<=10000, -10^9<=yi<=10^9, 1<=ri<=10^9
题解
需要考虑很多情况。比如第x年到第y年
如果y<x,不知道有没这种情况,应该是false吧
true的情况需要满足
x与y的值都已知且y值<x值且x+1到y-1都已知并且都小于y值
maybe满足
1.x值y值均未知
2.已知x值未知y值并且x+1到y-1都已知并且都小于y值
3.已知y值未知x值并且x+1到y-1都已知并且都小于x值
4.x为年份最大一年,y>x
5.y为年份最小一年,x<y
6.x,y均已知且y<x并且x+1到y-1有未知并且都小于x值
其它都是false
大概这样。。。
这种题一遍AC的是神
***调了几个小时
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 |
#include<iostream> #include<cstdio> using namespace std; struct data{int ly,ry,mx,know;}tr[200001]; int n,m; void build(int k,int l,int r) { if(l==r){scanf("%d%d",&tr[k].ly,&tr[k].mx);tr[k].ry=tr[k].ly;tr[k].know=1;return;} int mid=(l+r)>>1; build(k<<1,l,mid);build(k<<1|1,mid+1,r); tr[k].know=(tr[k<<1].know&&tr[k<<1|1].know); if(tr[k<<1].ry+1!=tr[k<<1|1].ly)tr[k].know=0; tr[k].ly=tr[k<<1].ly;tr[k].ry=tr[k<<1|1].ry; tr[k].mx=max(tr[k<<1].mx,tr[k<<1|1].mx); } int get(int k,int x) { if(tr[k].ly==tr[k].ry) { if(tr[k].ly!=x)return 0; else return tr[k].mx; } if(x<=tr[k<<1].ry)return get(k<<1,x); else if(x>=tr[k<<1|1].ly)return get(k<<1|1,x); return 0; } int ask(int k,int x,int y,int num) { bool f=0; if(x<tr[k].ly){f=1;x=tr[k].ly;} if(tr[k].ly==x&&tr[k].ry==y) { if(tr[k].mx>=num)return 0; else if(tr[k].know&&!f)return 1; else return 2; } if(y<=tr[k<<1].ry) { return ask(k<<1,x,y,num); } else if(x>=tr[k<<1|1].ly) { return ask(k<<1|1,x,y,num); } else { int t1=ask(k<<1,x,tr[k<<1].ry,num); int t2=ask(k<<1|1,tr[k<<1|1].ly,y,num); if(!t1||!t2)return 0; else if(tr[k<<1].ry+1!=tr[k<<1|1].ly)return 2; else return 1; } } int getnext(int k,int x) { int l=tr[k].ly,r=tr[k].ry; if(l==r)return tr[k].ly; if(x<tr[k<<1].ry)return getnext(k<<1,x); else return getnext(k<<1|1,x); } int getlast(int k,int x) { int l=tr[k].ly,r=tr[k].ry; if(l==r)return tr[k].ly; if(x>tr[k<<1|1].ly)return getlast(k<<1|1,x); else return getlast(k<<1,x); } int main() { scanf("%d",&n); build(1,1,n); scanf("%d",&m); for(int i=1;i<=m;i++) { int l,r; scanf("%d%d",&l,&r); if(r<l){printf("false\n");continue;} int lnum=get(1,l),rnum=get(1,r); if(!lnum&&!rnum)printf("maybe\n"); else { int s=getnext(1,l),t=getlast(1,r); if(!lnum) { if(s>t||r==t){printf("maybe\n");continue;} int f=ask(1,s,t,rnum); if(f==0)printf("false\n"); else printf("maybe\n"); } else if(!rnum) { if(s>t||l==s){printf("maybe\n");continue;} int f=ask(1,s,t,lnum); if(f==0)printf("false\n"); else printf("maybe\n"); } else { if(rnum>lnum){printf("false\n");continue;} if(s>t){ if(l+1==r) printf("true\n"); else printf("maybe\n"); continue; } int f=ask(1,s,t,rnum); if(f==0)printf("false\n"); else if(f==1) { if(l+1==s&&r-1==t)printf("true\n"); else printf("maybe\n"); } else if(ask(1,s,t,rnum)==2)printf("maybe\n"); else printf("false\n"); } } } return 0; } |
请问黄学长可否离线处理。
先对年份【离散化一下】,然后树状数组维护年份的存在,然后将存在点跑一下单调栈搞出以该年份值大的最左最右范围,之后一系列的判断。。可行么?主要感觉离散化以后好像有点问题(代码wa了),明天再看看。。。也希望黄学长能帮助一下弱弱。。
赞一个
写得太好了