BZOJ 1067 [RMQ]

1067: [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
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

这题一看就要维护区间最值。因为没有修改操作,所以就用RMQ,另外的话就是要离散。接下去就是要认真审题了。。。。。。。。。

“X年是自Y年以来降雨量最多的。”到底什么意思呢。。
它的含义是X年的降雨量不超过Y年,且对于任意Y<Z<X,Z年的降雨量严格小于X以及Y年。
那么再注意一下有些不知道降雨量的年份的处理,这题就过了。

附代码:

#include <cstdio>
#include <cstdlib>
#include <iostream>
#include <cstring>
#include <algorithm>
#define N 50005
using namespace std;

int f[N * 2][30], c[N];
int n, q, x, y, nx, ny;
struct cpp {
  int year, num;
  inline bool operator <(const cpp &a) const {
    return year < a.year;
  }
  inline bool operator <=(const cpp &a) const {
    return num <= a.num;
  }
  cpp(void) {}
  cpp(int y, int n):year(y), num(n) {}
}a[N];

inline int find(int x) {
  int l = 1, r = n, mid;
  while (l < r) {
    mid = (l + r) >> 1;
    if (x > a[mid].year) l = mid + 1;
    else r = mid;
  }
  return r;
}
inline int query(int l, int r) { // [l, r]
  int len = (r - l + 1), i, Max;
  for(i = 1; (Max = (1 << (i - 1))) <= len; i++);
  i--; Max >>= 1;
  return max(f[l][i], f[r - Max + 1][i]);
}

int main(void) {
  scanf("%d", &n);
  for (int i = 1; i <= n; i++) scanf("%d%d", &a[i].year, &a[i].num);
  memset(f, 0, sizeof(f));
  for (int i = 1; i <= n; i++) f[i][1] = a[i].num;
  for (int j = 2; (x = (1 << (j - 1))) <= n; j++)
    for (int i = 1; i <= n; i++) {
      f[i][j] = max(f[i][j - 1], f[i + (x >> 1)][j - 1]);
    }//RMQ是自己乱打的一点都不高贵...
  scanf("%d", &q);
  for (int i = 0; i < q; i++) {
    scanf("%d%d", &x, &y);
    if (i == 32) {
        x = x;
    }
    nx = lower_bound(a + 1, a + n + 1, cpp(x, 0)) - a;
    ny = lower_bound(a + 1, a + n + 1, cpp(y, 0)) - a;
    if (a[ny].year > y) ny--;
    if (a[nx].year == x && a[ny].year == y) {
      int p = query(nx + 1, ny - 1);
      if (nx - ny == x - y) {
        if (a[ny] <= a[nx] && p < a[ny].num) {puts("true"); continue;}
        else {puts("false"); continue;}
      } else {
        if (a[ny] <= a[nx] && p < a[ny].num) {puts("maybe"); continue;}
        else {puts("false"); continue;}
      }
    } else if (a[nx].year == x && a[ny].year != y) {
      int p = query(nx + 1, ny);
      if (a[nx].num > p) {puts("maybe"); continue;}
      else {puts("false"); continue;}
    }
    else if (a[nx].year != x && a[ny].year == y) {
      int p = query(nx, ny - 1);
      if (p < a[ny].num) {puts("maybe"); continue;}
      else {puts("false"); continue;}
    } else {
        puts("maybe"); continue;
    }
  }
  return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值