二维线段树 hdu 1823 ——luck and love

小w征婚问题

问题描述

小w征婚,收到很多女生报名,小w想找出其中符合要求的最有缘分的人。

输入

  • 第一行输入一个整数t,代表有t个操作。
  • 之后的t行每行输入一种操作:
    • 操作“I”,表示一个女生报名,输入女生的三个信息:身高H(整数),活泼度A(浮点数),缘分L(浮点数)。
    • 操作“Q”,表示一个查询操作,输入四个浮点数:H1,H2表示身高区间,A1,A2表示活泼度区间。

输出

  • 对于每次查询操作,输出符合身高和活泼度区间中的缘分最大值。若没有符合条件的女生,则输出-1。

区间范围

  • 100.0 <= H1, H2 <= 200.0
  • 0 <= A1, A2, L <= 100.0

示例

输入示例

5
I 165 30.5 55.0
I 170 25.0 70.0
Q 160.0 180.0 20.0 40.0
I 168 35.0 85.0
Q 165.0 175.0 25.0 35.0

输出示例

-1
85.0
解释:

  • 第一次查询,没有女生的身高在[160.0, 180.0]且活泼度在[20.0, 40.0]之间,所以输出-1。
  • 第二次查询,有一个女生的身高在[165.0, 175.0]且活泼度在[25.0, 35.0]之间(即新加入的女生),她的缘分值是85.0,所以输出85.0。
#include<iostream>
#include<algorithm>
using namespace std;
int ls(int p) { return p << 1; }
int rs(int p) { return p << 1 | 1; }
int n = 1000, s[1005][4005];   //s[i][j],表述身高区间i,活泼区间j中的最大缘分,注意这书二维线段树,所以i,j都代表以[ls(i/j),rs(i/j)]为区间的线段树节点,(线段树中除了叶子节点其余节点都为区间)
//建立二维线段树
void subbuild(int xp, int p, int pl, int pr) {
	//xp代表身高区间,p代表活泼度区间
	s[xp][p] = -1;  //初始化为一个最小数
	if (pl == pr) return; 
	int mid = (pl + pr) >> 1;  //递归到叶子节点
	//只更新一棵树上的节点,其实二维数组中有很多空间被浪费,这是树结构的特性所致
	subbuild(xp, ls(p), pl, mid);
	subbuild(xp, rs(p), mid + 1, pr);
}

void build(int p, int pl, int pr) {
	subbuild(p, 1, 0, n);
	if (pl == pr) return;
	int mid = (pl + pr) >> 1;
	build(ls(p), pl, mid);
	build(rs(p), mid + 1, pr);
}

void subupdate(int xp, int y, int c, int p, int pl, int pr) {
	if (pl == pr && pl == y) s[xp][p] = max(s[xp][p], c);  //到达叶子节点
	else {
		int mid = (pl + pr) >> 1;
		if (y <= mid) subupdate(xp, y, c, ls(p), pl, mid);
		else subupdate(xp, y, c, rs(p),mid + 1, pr);
		s[xp][p] = max(s[xp][ls(p)], s[xp][rs(p)]);  //线段树的pushup函数,需要更新所有区间
	}
}

void update(int x, int y, int c, int p, int pl, int pr) {
	subupdate(p, y, c, 1, 0, n);
	if (pl != pr) {
		int mid = (pl + pr) >> 1;
		if (x <= mid) update(x, y, c, ls(p), pl, mid);
		else update(x, y, c, rs(p), mid + 1, pr);
	}
}

int subquery(int xp, int yl, int yr, int p, int pl, int pr) {
	if (yl <= pl && pr <= yr) return s[xp][p];  //搜索到了符合活泼度的区间
	else {
		int mid = (pl + pr) >> 1;
		int res = -1;
		if (yl <= mid) res = subquery(xp, yl, yr, ls(p), pl, mid);
		if (yr > mid) res = max(res, subquery(xp, yl, yr, rs(p), mid + 1, pr));
		return res;
	}
}

int query(int xl, int xr, int yl, int yr, int p, int pl, int pr) {
	if (xl <= pl && pr >= xr) return subquery(p, yl, yr, 1, 0, n); //搜索到了符合身高的区间
	else {
		int mid = (pl + pr) >> 1;
		int res = -1;
		if (xl <= mid) res = query(xl, xr, yl, yr, ls(p), pl, mid);
		else res = max(res, query(xl, xr, yl, yr, rs(p), mid + 1, pr));
		return res;
	}
}

int main() {
	int t;
	while (scanf("%d", &t) && t) {
		build(1, 100, 200);
		while (t--) {
			char ch[2]; scanf("%s", ch);
			if (ch[0] == 'I') {
				int h; double c, d; cin >> h >> c >> d;
				update(h, c * 10, d * 10, 1, 100, 200); //c和d为浮点数需要凑整,否则无法使用"<<"移位符号
			}
			else {
				int xl, xr, yl, yr; double c, d;
				cin >> xl >> xr >> c >> d;
				yl = c * 10; yr = d * 10;  //活泼度区间也为浮点数也需要转化为整数,原因同上
				//防止大小颠倒
				if (xl > xr) swap(xl, xr);
				if (yl > yr) swap(yl, yr);
				int ans = query(xl, xr, yl, yr, 1, 100, 200); //[100,200]为身高区间
				if (ans == -1) cout << ans;
				else cout << ans / 10.0;
			}
		}
	}
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值