BZOJ 1067 [SCOI 2007] 线段树 解题报告

本文介绍了一种用于查询特定年份是否为某段时间内降雨量最多的算法。通过使用二分查找和线段树来高效地确定某年是否为自另一年以来降雨量最多的年份。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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

【解题报告】

i,j均未知输出可能;
i知j未知,因为j最大可以和i相等,所以如果i到j之间有大于i的需输出错,否则输出可能;
i未知j知,如果i到j之间有大于j的输出错否则输出可能;
i知j知如果i到j中已知的大于j或j的信息大于i,则输出错,如果没有大于j的且i到j所有年份已知输出可能,否则输出对。
二分查年份+线段树查最大值

解题报告

/**************************************************************
    Problem: 1067
    User: onepointo
    Language: C++
    Result: Accepted
    Time:248 ms
    Memory:2384 kb
****************************************************************/

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define N 100010
#define inf 0x3f3f3f3f
#define lson rt<<1,l,m
#define rson rt<<1|1,m+1,r

int n,m,minx=inf;
int x[N],y[N],mx[N<<1];

void pushup(int rt)
{
    mx[rt]=max(mx[rt<<1],mx[rt<<1|1]);
}
void build(int rt,int l,int r)
{
    if(l==r) {mx[rt]=y[l];return;}
    int m=(l+r)>>1;
    build(lson);build(rson);
    pushup(rt);
}
int query(int rt,int l,int r,int L,int R)
{
    if(L<=l&&r<=R) return mx[rt];
    int ret=0,m=(l+r)>>1;
    if(L<=m) ret=max(ret,query(lson,L,R));
    if(R>m) ret=max(ret,query(rson,L,R));
    return ret;
}
int find(int y,bool flag)
{
    int l=1,r=n;
    if(flag)
    {
        while(l<r)
        {
            int mid=l+((r-l)>>1);
            if(y<=x[mid])r=mid;
            else l=mid+1;
        }
    }
    else
    {
        while(l<r)
        {
            int mid=r-((r-l)>>1);
            if(y<x[mid])r=mid-1;
            else l=mid;
        }
    }
    return l;
}
int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;++i) 
    {
        scanf("%d%d",&x[i],&y[i]);
        minx=min(minx,x[i]);
    }
    build(1,1,n);
    scanf("%d",&m);
    for(int i=1;i<=m;++i)
    {
        int a,b;scanf("%d%d",&a,&b); 
        int c=find(a,1),d=find(b,1);
        if(a>=b) {puts("false");continue;}
        if(b!=x[d])
        {
            if(a!=x[c]){puts("maybe");continue;} 
            if(c==n){puts("maybe");continue;}
            if(query(1,1,n,c+1,find(b,0))>=y[c]){puts("false");continue;}
            puts("maybe");continue;
        }
        if(a!=x[c])
        {
            if(d==1){puts("maybe");continue;}
            if(a<minx)
            {
                if(query(1,1,n,1,d-1)>=y[d]) puts("false");
                else puts("maybe");
            }
            else
            {
                if(query(1,1,n,find(a,1),d-1)>=y[d]) puts("false");
                else puts("maybe");
            }
            continue;
        }
        if(y[d]>y[c]||query(1,1,n,c+1,d-1)>=y[d]) puts("false");
        else
        {
            if(d-c!=b-a)puts("maybe");
            else puts("true");
        }
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值