P2471 [SCOI2007]降雨量

题目描述

我们常常会说这样的话:“X 年是自 Y 年以来降雨量最多的”。它的含义是 X 年的降雨量不超过 Y 年,且对于任意 Y<Z<X,Z 年的降雨量严格小于 X 年。例如 2002,2003,2004 和 2005 年的降雨量分别为 4920,5901,2832 和 3890,则可以说“2005 年是自 2003 年以来最多的”,但不能说“2005 年是自 2002 年以来最多的”由于有些年份的降雨量未知,有的说法是可能正确也可以不正确的。题目link

思路

先判false:
1、当右端点年份确定,且中间年份最大降雨量大于等于右端点降雨量
2、当左端点年份确定,且中间年份最大降雨量大于等于左端点降雨量
3、当左右端点年份都确定,且左端点降雨量小于等于右端点降雨量
再判maybe:
1、当左右端点之差不等于左右端点年份之差(等价于年份不连续,也就是我前面所说的更好的判断区间连续的方法)
2、左端点年份不确定
3、右端点年份不确定
(因为已经切掉false的情况了,那么剩下的情况中可以直接照上面的判断!)
最后判断true

#include <bits/stdc++.h>
using namespace std;
#define int long long

const int N = 50010;
int y[N], rr[N];

int n, m;
const int M = 17;

int f[N][M];//表示i开始,长度为2^j的最大值

void init() {
    for(int j=0; j<M; ++j)//长度从2^0到2^M枚举
        for(int i=1; i+(1<<j)-1<=n; ++i) {//位置从1到1+len-1<=n
            if(!j) f[i][j] = rr[i];
            else f[i][j] = max(f[i][j-1], f[i+(1<<j-1)][j-1]);//从i+2^(j-1)
        }
}

int query(int l, int r) {//下表为l~r中返回最大的数
    int len = r - l + 1;
    int k = log2(len);
    return max(f[l][k], f[r-(1<<k)+1][k]);//f[l,k], f[r-2^k,k]
}

signed main()
{
    cin>>n;
    for(int i=1; i<=n; ++i) {
        scanf("%lld%lld", &y[i], &rr[i]);
    }
    
    init();
    
    cin>>m;
    while(m--) {
        int y1, y2;
        scanf("%lld%lld", &y1, &y2);
        if(y1>=y2){printf("false\n");continue;}
        int st=lower_bound(y+1,y+n+1,y1)-y,ed=lower_bound(y+1,y+n+1,y2)-y;
        bool fl,fr;int op=0;
        fl=y[st]==y1,fr=y[ed]==y2;
        if(!fl)st--;
        if(st+1<=ed-1)op=query(st+1,ed-1);
        if((op>=rr[ed]&&fr)||(rr[st]<rr[ed]&&fl&&fr)||(op>=rr[st]&&fl))printf("false\n");
        else if(ed-st!=y[ed]-y[st]||!fr||!fl)printf("maybe\n");
        else printf("true\n");
    }
    return 0;
}
posted @ 2021-08-15 22:25  misaka-mikoto  阅读(61)  评论(0编辑  收藏  举报