解题思路:
这个题目是一个二维线段树(属于树套树)的入门题,
一维每一行用来代表一个身高区域;
二维每一列用来代表一个或与都区域;
整个二维数组维护的是缘分值的最大值。
一维的线段树如果操作,二维的线段树也怎么操作。
每次就是线段树先考虑一维的,然后在考虑二维的。
题目给出的活跃度和缘分值都明确说明是一位小数,
因此我们将活跃度放大10倍,这样就可以维护整型
的区间。
AC代码:
#include <iostream>
#include <stdio.h>
#include <string.h>
#include <algorithm>
#define lchild left,mid,root<<1
#define rchild mid+1,right,root<<1|1
using namespace std;
const int maxm = 210; ///一维一个行代表身高区域
const int maxn = 1010; ///二维一个列代表活跃度区域
int a[maxm<<2][maxn<<2]; ///整个数组维护的是缘分值
int M;
void push_up(int row,int root)
{
a[row][root] = max(a[row][root<<1],a[row][root<<1|1]);
}
void insert2(int row,int active,int love,int left,int right,int root)
{
if(left == right) ///到了叶子节点
{
///这里注意,可能插入两条相同的记录,避免小值覆盖大值
a[row][root] = max(a[row][root],love);
return;
}
int mid = (left+right)>>1;
///递归插入左子树
if(active<=mid) insert2(row,active,love,lchild);
else insert2(row,active,love,rchild);
///递归插入右子树
///更新当前节点的最大值
push_up(row,root);
}
void insert1(int height,int active,int love,int left,int right,int root)
{
insert2(root,active,love,0,1000,1);
///原来我把这句写在了left==right里面,后来发现第一条答案不对,才意识到这句应该在外边。
if(left == right)
{
return;
}
int mid = (left+right)>>1;
if(height<=mid) insert1(height,active,love,lchild);
else insert1(height,active,love,rchild);
}
int query2(int row,int active1,int active2,int left,int right,int root)
{
///当前节点区间是要查询范围的子区间,返回节点值
if(active1<=left && right<=active2)
{
return a[row][root];
}
int mid = (left+right)>>1;
int ans = -1;
///递归查找子区间。
if(active1 <= mid) ans = query2(row,active1,active2,lchild);
if(active2 > mid) ans = max(ans,query2(row,active1,active2,rchild));
return ans;
}
int query1(int height1,int height2,int active1,int active2,int left,int right,int root)
{
if(height1<=left && right<=height2)
{
return query2(root,active1,active2,0,1000,1);
}
int mid = (left + right)>>1;
int ans = -1;
if(height1 <= mid) ans = query1(height1,height2,active1,active2,lchild);
if(height2 > mid) ans = max(ans,query1(height1,height2,active1,active2,rchild));
return ans;
}
int main()
{
while(~scanf("%d",&M))
{
if(M == 0) break;
char ch;
///直接将数组刷成-1.
memset(a,-1,sizeof(a));
for(int i = 1; i <= M; i++)
{
scanf(" %c",&ch);
if(ch == 'I') ///如果是I,插入一条记录
{
int height;
double Active;
double Love;
scanf("%d%lf%lf",&height,&Active,&Love);
int A = (int)(Active*10); ///把活跃度放大十倍,题目说了题中小数都是一位小数
int L = (int)(Love*10); ///把L也放大十倍,这里放不放大都行
insert1(height,A,L,0,200,1);
}
else ///如果是Q,查询相关记录
{
int height1,height2,temp;
double active1,active2;
scanf("%d%d%lf%lf",&height1,&height2,&active1,&active2);
int A1 = (int)(active1*10);
int A2 = (int)(active2*10);
///题目的小坑,输入的数据不一定从小到大。
if(height1 > height2)
{
temp = height1;
height1 = height2;
height2 = temp;
}
if(A1 > A2)
{
temp = A1;
A1 = A2;
A2 = temp;
}
int ans = query1(height1,height2,A1,A2,0,200,1);
if(ans == -1)
printf("-1\n");
else
printf("%.1lf\n",ans*0.1);
}
}
}
return 0;
}