1. 程式人生 > >[BZOJ 1067][SCOI2007]降雨量

[BZOJ 1067][SCOI2007]降雨量

ems 第一個 blog 比較 查找 name int 單調棧 ()

題目:http://www.lydsy.com/JudgeOnline/problem.php?id=1067

題解:

  咳咳.這次因為遇到了一些比較有成就感的事情所以來發博。

  聽說這題要用線段樹??開玩笑。當然不。

  首先我們想想,如果我們知道了X年份的降雨量的時候,向前找已知降雨量比X大或等於的第一個年份(我們設為Z1),如果Y年份比Z1小則Y到X這個區間一定包含Z1,那麽此命題為FALSE;如果我們知道Y年份降雨量,則向後找已知降雨量大於或等於Y的第一個年份Z2,如果X>Z2那麽Y到X這個區間一定包含Z2,則此命題必為FALSE;如果我們知道X和Y年的降雨量,則此命題為TRUE當且僅當Z1==Y且Y到X全部年份已知,否則為FALSE.

  那麽剩下的只能是MAYBE了.

  如何快速向前找比當前年份降雨量大或等於的第一個年份,此處我運用了一個單調棧來快速查找.然後向後找的話反過來一遍就行了.

代碼

#include <cstdio>
#include <cstring>

using namespace std;

const int maxn = 50005;

int year[maxn], rain[maxn], af[maxn], beh[maxn];
int S[maxn], top, n, m;

int find(int x)
{
    int l = 1, r = n;
    while
(l < r) { int mid = (l+r) >> 1; if (year[mid] < x) l = mid + 1; else r = mid; } return l; } int main() { scanf("%d", &n); top = 0; year[0] = -0x7fffffff; rain[0] = 0x7fffffff; S[0] = 0; memset(beh, 0, sizeof(beh)); for (int i = 1
; i <= n; ++i) { scanf("%d%d", &year[i], &rain[i]); while (rain[S[top]] < rain[i]) --top; af[i] = S[top]; S[++top] = i; } top = 0; for (int i = n; i >= 1; --i) { while (rain[S[top]] < rain[i]) --top; beh[i] = S[top]; S[++top] = i; } scanf("%d", &m); for (int i = 0; i < m; ++i) { int x, y; scanf("%d%d", &y, &x); if (y >= x) printf("false"); else { int nx = find(x), ny = find(y); if (year[nx] != x) { if (year[ny] != y) printf("maybe"); else if (year[beh[ny]] > x || beh[ny] == 0) printf("maybe"); else printf("false"); } else { if (year[ny] != y) { if (y < year[af[nx]]) printf("false"); else printf("maybe"); } else { if (ny != af[nx]) printf("false"); else if (x-y == nx-ny) printf("true"); else printf("maybe"); } } } printf("\n"); } return 0; }

[BZOJ 1067][SCOI2007]降雨量