降雨量 LibreOJ - 2279
原题链接
考察:线段树 or RMQ + 离散化
错误思路:
对于查询中,没给出降雨量的年份,假定降雨量为0,再建立线段树.
错误原因:
maybe的依据是区间最小值为0,但是即使有不确定的年份也可以确定false,而且插入虚点了就不方便判定中间值与\(l,r\)的大小情况.
正确思路:
对于每个查询,分情况讨论:
- 左端点确定,右端点确定
- 左端点不确定,右端点确定
- 左端点确定,右端点不确定.
Code
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 50010;
struct Node{
int l,r,maxn;
}tr[N<<2];
struct Year{
int y,down;
bool operator<(const Year& s){
return this->y<s.y;
}
}year[N];
int n,m;
int get(int y)
{
int l = 1,r = n;
while(l<r)
{
int mid = l+r>>1;
if(year[mid].y>=y) r = mid;
else l = mid+1;
}
return l;
}
void push_up(int u)
{
tr[u].maxn = max(tr[u<<1].maxn,tr[u<<1|1].maxn);
}
void build(int u,int l,int r)
{
tr[u] = {l,r,0};
if(l==r) {tr[u].maxn = year[l].down;return;}
int mid = l+r>>1;
build(u<<1,l,mid); build(u<<1|1,mid+1,r);
push_up(u);
}
int query_max(int u,int l,int r)
{
if(tr[u].l>=l&&tr[u].r<=r) return tr[u].maxn;
int mid = tr[u].l+tr[u].r>>1,res = 0;
if(l<=mid) res = max(query_max(u<<1,l,r),res);
if(mid<r) res = max(query_max(u<<1|1,l,r),res);
return res;
}
int check(int a,int b,int l,int r)
{//-1 false 0 maybe 1 true
if(l>r) return -1;
if(a==b) return 1;
if(l==r&&a!=b) return 0;
if(year[l].y!=a&&year[r].y!=b) return 0;
if(year[l].y!=a)
{
int m1 = year[r].down,m2 = query_max(1,l,r-1);
if(m1<=m2) return -1;
return 0;
}
if(year[r].y!=b)
{
int m1 = year[l].down,m2 = -1;
if(l+1<r) m2 = query_max(1,l+1,r-1);
if(m1<=m2) return -1;
return 0;
}
if(year[l].down<year[r].down) return -1;
int m1 = year[r].down,m2 = query_max(1,l+1,r-1);
if(m1<=m2) return -1;
if(r-l!=b-a) return 0;
return 1;
}
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
int y,d; scanf("%d%d",&y,&d);
year[i] = {y,d};
}
build(1,1,n);
scanf("%d",&m);
int cnt = 0;
while(m--)
{
int a,b;
scanf("%d%d",&a,&b);
int v = check(a,b,get(a),get(b));
if(v==-1) puts("false");
else if(!v) puts("maybe");
else puts("true");
}
return 0;
}