静态二叉检索树。
其实说来奇怪,
学ACM这么长时间了,而且我还是负责基础数据结构的,
居然连这个都没写过。
//我发现我现在做的题都好水啊咋办咋办。。
题目链接:http://poj.org/problem?id=2482
题意:
给出平面上的一些点,每个点有权值
问用一个w*h的矩形最多框住的点权和是多少
矩形边框上的点不算在矩形内
算法:
把每个点拆成四个点,(x,y,val),(x,y+h,-val),(x+w,y,-val),(x+w,y+h,val)
对y进行离散化
由于是每个点加入之后都查询一次最大值,
所以插入时,值为负的应当在前。也就是排序时应该按照(x,val)点对排序,而不是按照(x,y,val)三元组排序
然后用二叉检索树对于每个节点维护两个值。
对于节点rt,假设它所在的子树种最靠左的点(即y值最小的点)是l,那么
sum[rt]=sum of [l,rt]
tr[rt]=max(sum of(l,x)) x是节点rt及其两棵子树种的任意点
trick: x,y虽然是int范围,但加上w,h后就会越界。
代码如下:
#include<cstdio>
#include<iostream>
#include<sstream>
#include<cstdlib>
#include<cstring>
#include<string>
#include<climits>
#include<cmath>
#include<algorithm>
#include<queue>
#include<vector>
#include<stack>
#include<set>
#include<map>
#define INF 0x3f3f3f3f
#define eps 1e-8
using namespace std;
const int MAXN=11000;
vector<long long>hash;
vector<pair<pair<long long, int>, long long> >node;
int tr[MAXN<<3],sum[MAXN<<3];
void update(int l, int r, int x, int c, int rt) {
int mid=(l+r)>>1;
if(mid==x) {
sum[rt]+=c;
} else if(x<mid) {
update(l,mid-1,x,c,rt<<1);
sum[rt]+=c;
} else {
update(mid+1,r,x,c,rt<<1|1);
}
tr[rt]=sum[rt];
if(l<mid) {
tr[rt]=max(tr[rt],tr[rt<<1]);
}
if(r>mid) {
tr[rt]=max(tr[rt],sum[rt]+tr[rt<<1|1]);
}
}
int main() {
int n,w,h;
while(scanf("%d%d%d",&n,&w,&h)==3) {
hash.clear();
node.clear();
for(int i=0; i<n; i++) {
long long x,y;
int val;
scanf("%lld%lld%d",&x,&y,&val);
node.push_back(make_pair(make_pair(x,val),y));
node.push_back(make_pair(make_pair(x+w,-val),y));
node.push_back(make_pair(make_pair(x,-val),y+h));
node.push_back(make_pair(make_pair(x+w,val),y+h));
hash.push_back(y);
hash.push_back(y+h);
}
sort(hash.begin(),hash.end());
hash.erase(unique(hash.begin(),hash.end()),hash.end());
sort(node.begin(),node.end());
memset(tr,0,sizeof(tr));
memset(sum,0,sizeof(sum));
int ans=0;
int lim=hash.size();
for(int i=0; i<node.size(); i++) {
update(0,lim-1,lower_bound(hash.begin(),hash.end(),node[i].second)-hash.begin(),node[i].first.second,1);
ans=max(ans,tr[1]);
}
printf("%d\n",ans);
}
return 0;
}