BZOJ_P1067&Codevs_P2439 [SCOI2007]降雨量(线段树)

11 篇文章 0 订阅

Time Limit: 1 Sec Memory Limit: 162 MB
Submit: 2915 Solved: 745

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

100%的数据满足:1<=n<=50000, 1<=m<=10000, -10^9<=yi<=10^9, 1<=ri<=10^9

Source
POJ 2637 WorstWeather Ever

我去简直了,恶心到爆,让我冷静一下

#include<cstdio>
#include<map>
#include<iostream>
using namespace std;
#define N 150000 //数据范围 
//变量声明 
struct node{
    int ma,l,r;      //最大值,左右 
    bool un;     //是否存在未知 
}s[N*2];         //节点 
map<int,int> cl; //年份对应降雨量 
int n,t,m;       //数据数目,总数,询问数目 
int y[N],w[N];   //年份与降雨量 

//函数声明
void build(int o,int l,int r);//建立线段树 
bool find(int x);//年份出现 
void init(node& x);//初始化节点 
void by(node a,node b,node& p);//节点合并
node query(int o,int l,int r);//查询函数 
int ef(int x,bool ord);//二分查找 
int in();//读入优化 

//主函数 
int main(){
    n=in();int tt;
    for(int i=1;i<=n;i++){
        y[i]=in(),tt=in(); 
        if(i!=1&&y[i]-1!=y[i-1]) w[++t]=-1;
        w[++t]=tt;
        cl[y[i]]=t;
    }
    build(1,1,t);m=in();
    int ll,rr;bool xx,yy;node ans;               //左右端点   是否出现 
    while(m--){
        ll=in(),rr=in();
        xx=find(ll),yy=find(rr);
        if((!xx)&&(!yy)){printf("maybe\n");continue;}//都未知,就是maybe 
        if(xx&&yy){            //均已知 
            if(ll==rr) {printf("maybe\n");continue;}
            ll=cl[ll],rr=cl[rr];
            if(w[ll]<w[rr]){printf("false\n");continue;}
            ans=query(1,ll+1,rr-1);
            if(ans.ma>=w[rr]) {printf("false\n");continue;}
            if(ans.un) {printf("maybe\n");continue;}
            {printf("true\n");continue;}
        }
        else if(xx&&(!yy)){    //后未知 
            rr=ef(rr,true);
            if(ll==rr) {printf("maybe\n");continue;}
            ll=cl[ll],rr=cl[rr];
            ans=query(1,ll+1,rr);
            if(w[ll]<=ans.ma) {printf("false\n");continue;}
            {printf("maybe\n");continue;}
        }
        else{                  //前未知 
            ll=ef(ll,false);
            if(ll==rr) {printf("maybe\n");continue;}
            ll=cl[ll],rr=cl[rr];
            ans=query(1,ll,rr-1);
            if(w[rr]<=ans.ma) {printf("false\n");continue;}
            {printf("maybe\n");continue;}
        }
    }
    return 0;
}



//建立线段树 
void build(int o,int l,int r){
    if(l==r){
        s[o].ma=w[l];s[o].l=s[o].r=l;
        if(w[l]<0) s[o].un=true;
        return;
    }
    int m=(l+r)>>1;
    build(o*2,l,m);build(o*2+1,m+1,r);
    s[o].ma=max(s[o*2].ma,s[o*2+1].ma);
    s[o].un=(s[o*2].un||s[o*2+1].un);
    s[o].l=l,s[o].r=r;
    return;
}


//查找年份是否出现 
bool find(int x){
    return cl.find(x)!=cl.end();     //找到返回true 未找到返回false 
}

//初始化节点 
void init(node& x){
    x.ma=0,x.un=false;return;
}

//节点合并
void by(node a,node b,node& p){
    p.ma=max(a.ma,b.ma);p.un=(a.un||b.un);
    return;
}

//查询函数 
node query(int o,int l,int r){
    if(l<=s[o].l&&r>=s[o].r) return s[o];
    int m=(s[o].l+s[o].r)>>1;node p,k,res;
    init(p);init(k);
    if(l<=m) p=query(o*2,l,r);
    if(r>m) k=query(o*2+1,l,r);
    by(p,k,res);
    return res;
}

//二分查找 
int ef(int x,bool ord){         //ord=true,maxl;ord=false,minr;
    int l=1,r=n,m;
    while(l<r){
        m=(l+r)>>1;
        if(y[m]<x) l=m+1;
        else r=m;
    }
    if(ord) if(y[l]>x) l--;
    if(!ord) if(y[l]<x) l++;
    return y[l];
}


//读入优化
int in(){
    int x=0,v=1;char ch=getchar();
    while(ch!='-'&&(ch>'9'||ch<'0')) ch=getchar();
    if(ch=='-') ch=getchar(),v=-1;
    while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
    return x*v;
} 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值