SCOI2007降雨量(线段树+讨论)

Posted mcggvc

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了SCOI2007降雨量(线段树+讨论)相关的知识,希望对你有一定的参考价值。

链接
显然是用map映射一下,然后用线段树查询区间最值,如果给出的两年中有一年未知,二分找到它附近的位置(如果是x未知找第一个大于x的位置,如果是y未知找最大的小于y的位置)
然后再加亿点点细节:
我们就可以用这几个量来判断。

rain[i]:i位置的降雨量
year[i]:i位置的年份
x,y:题目中给定的年份
posx:当前x年的位置
posy:当前y年的位置
posz:(x, y)区间中最大雨量所在年份的位置

讨论主要分为四部分:
1.x,y都未知
2.x未知,y已知
3.x已知,y未知
4.x, y都已知
对于1情况:
maybe
对于2情况:
1.x是否等于y + 1
2.rain[posz] < rain[posy]还是rain[posz] >= rain[posy]
对于3情况:
1.x是否等于y + 1
2.rain[posz] < rain[posx]还是rain[posz] >= rain[posx]
对于4情况:
1.rain[posx] > rain[posy] false
2.x是否等于y + 1
3.x - y 是否等于posx - posy
4.rain[posz] < rain[posx]还是rain[posz] >= rain[posx]
其他细节:
1.如上文所说,lower_bound二分时posy要-1
2.求posz时注意posx和posy的关系,如果posx = posy + 1,一个-1一个+1时会报错

代码:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <map>
using namespace std;
const int N = 50005;
struct node {
	int r, y;//当前区间最大雨量和所在年份
} tree[N << 4];
int year[N], rain[N];
map<int, int> pos;
int n, m;
void update(int i) {
	if(tree[i << 1].r >= tree[i << 1 | 1].r) {
		tree[i].r = tree[i << 1].r, tree[i].y = tree[i << 1].y;
	} else {
		tree[i].r = tree[i << 1 | 1].r, tree[i].y = tree[i << 1 | 1].y;
	}
}
void build(int i, int l, int r) {
	if(l == r) {
		tree[i].y = year[l], tree[i].r = rain[l];
		return ;
	}
	int mid = (l + r) >> 1;
	build(i << 1, l, mid);
	build(i << 1 | 1, mid + 1, r);
	update(i);
}
node query(int i, int l, int r, int nl, int nr) {//求区间最值
	if(l >= nl && r <= nr) return tree[i];
	int mid = (l + r) >> 1;
	if(nr <= mid) return query(i << 1, l, mid, nl, nr);
	if(nl > mid) return query(i << 1 | 1, mid + 1, r, nl, nr);
	node tmp1 = query(i << 1, l, mid, nl, nr);
	node tmp2 = query(i << 1 | 1, mid + 1, r, nl, nr);
	if(tmp1.r >= tmp2.r) return tmp1;
	else return tmp2;
}
int main() {
//	freopen("data.in", "r", stdin);
	scanf("%d", &n);
	for(int i = 1; i <= n; i++) {
		scanf("%d%d", &year[i], &rain[i]);
		pos[year[i]] = i;
	}
	build(1, 1, n);
	scanf("%d", &m);
	for(int i = 1; i <= m; i++) {
		int x, y; scanf("%d%d", &y, &x);
		int posx = pos[x], posy = pos[y];
		if(!posx && !posy) {//都未知
			printf("maybe
"); continue;
		}
		if(!posx && posy) {//x未知y已知
			posx = lower_bound(year + 1, year + 1 + n, x) - year;
			if(x == y + 1) {
				printf("maybe
"); continue;
			}
			int posz;
			if(posx == posy + 1) posz = 0;
			else posz = pos[query(1, 1, n, posy + 1, posx - 1).y];
			if(rain[posz] < rain[posy]) {
				printf("maybe
"); continue;
			} else if(rain[posz] >= rain[posy]) {
				printf("false
"); continue;
			}
		}
		if(posx && !posy) {//x已知y未知
			if(x == y + 1) {
				printf("maybe
"); continue;
			}
			posy = lower_bound(year + 1, year + 1 + n, y) - year - 1;
			int posz;
			if(posx == posy + 1) posz = 0;
			else posz = pos[query(1, 1, n, posy + 1, posx - 1).y];
			if(rain[posz] < rain[posx]) {
				printf("maybe
"); continue;
			} else if(rain[posz] >= rain[posx]) {
				printf("false
"); continue;
			}
		}//
		if(posx && posy) {//都已知
			if(rain[posx] > rain[posy]) {
				printf("false
"); continue;
			}
			if(x == y + 1) {
				if(x - y == posx - posy) {
					printf("true
"); continue;
				} else {
					printf("maybe
"); continue;
				}
			} else if(x != y + 1) {
				int posz;
				if(posx == posy + 1) posz = 0;
				else posz = pos[query(1, 1, n, posy + 1, posx - 1).y];
				if(x - y == posx - posy) {
					if(rain[posz] < rain[posx]) {
						printf("true
"); continue;
					} else {
						printf("false
"); continue;
					}
				} else {
					if(rain[posz] < rain[posx]) {
						printf("maybe
"); continue;
					} else {
						printf("false
"); continue;
					}
				}
			}
		}
	}
	return 0;
}























以上是关于SCOI2007降雨量(线段树+讨论)的主要内容,如果未能解决你的问题,请参考以下文章

1067. [SCOI2007]降雨量线段树

bzoj1067——SCOI2007降雨量(线段树,细节题)

bzoj 1067: [SCOI2007]降雨量

[luogu2471][SCOI2007]降雨量

洛谷 2471 BZOJ 1067 [SCOI2007]降雨量

bzoj 1067: [SCOI2007]降雨量