POJ2482 Stars in Your Window

Description

(一段令人感动的程序员的爱情故事...)


Here comes the problem: Assume the sky is a flat plane. All the stars lie on it with a location (x, y). for each star, there is a grade ranging from 1 to 100, representing its brightness, where 100 is the brightest and 1 is the weakest. The window is a rectangle whose edges are parallel to the x-axis or y-axis. Your task is to tell where I should put the window in order to maximize the sum of the brightness of the stars within the window. Note, the stars which are right on the edge of the window does not count. The window can be translated but rotation is not allowed. 

Input

There are several test cases in the input. The first line of each case contains 3 integers: n, W, H, indicating the number of stars, the horizontal length and the vertical height of the rectangle-shaped window. Then n lines follow, with 3 integers each: x, y, c, telling the location (x, y) and the brightness of each star. No two stars are on the same point. 

There are at least 1 and at most 10000 stars in the sky. 1<=W,H<=1000000, 0<=x,y<2^31. 

Output

For each test case, output the maximum brightness in a single line.

Sample Input

3 5 4
1 2 3
2 3 2
6 3 1
3 5 4
1 2 3
2 3 2
5 3 1

Sample Output

5
6

题意:给出若干星星的坐标及其亮度,给定一个矩形W*H,求可以围住的星星亮度之和的最大值(恰好在边上的不算)。

分析:将矩形抽象为矩形的中心点,每个星星可以被围住的范围可以看做以星星所在坐标为中心点的矩形,将所有星星对应的矩形分别赋予相应的权值c,则该平面内权值之和最大的区域即为所求的矩形中心点所在的位置。记录每个矩形左右两边的横坐标和上下界,分别赋予正负权值,利用扫描线从左到右扫描,更新线段树,将纵边对应的区间加上相应的权值,得到全局最大值即可得到最终结果。

需要注意的是恰好在边上的星星不算,所以需要考虑边界问题:两条纵边重合时,要先处理-c那条边;对于横边框,记录每条纵边上下界时可记为区间[y1,y2-1]。

 

#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=20010;
typedef long long ll;
ll Y[maxn];
struct node{
	int max,tag;
}tree[maxn<<2];
struct Edge{	
	ll low,high,x;//上下纵坐标、横坐标 
	int c;//亮度 	
	Edge(){}
	Edge(ll l,ll h,ll x,int c)
	:low(l),high(h),x(x),c(c){}
	
	bool operator<(const Edge other)
	{
		if(x==other.x)//横坐标重合时 先处理负权值边 
			return c<other.c;
		return x<other.x;
	} 
}edge[maxn];

void update(int L,int R,int root,int l,int r,int val)
{
	if(L<=l&&R>=r)
	{
		tree[root].max+=val;
		tree[root].tag+=val;
		return;
	}
	int mid=(l+r)/2;
	if(L<=mid) update(L,R,root<<1,l,mid,val);
	if(R>mid) update(L,R,root<<1|1,mid+1,r,val);
	
	tree[root].max=max(tree[root<<1].max,tree[root<<1|1].max)+tree[root].tag;
}

int main()
{
	int N,W,H,num;
	while(cin>>N>>W>>H)
	{	
		num=0;	
		//memset(tree,0,sizeof(tree));
		for(int i=0;i<N;i++)
		{
			ll x,y,c;
			scanf("%lld%lld%d",&x,&y,&c);
			x*=2;y*=2;//乘2以避免除法出现误差 
			edge[num]=Edge(y-H,y+H-1,x-W,c);//上界减一 
			Y[num++]=y-H;
			edge[num]=Edge(y-H,y+H-1,x+W,-c);//负权值 
			Y[num++]=y+H-1;//上界减一 
			
		}
		//对横坐标排序,从左到右扫描 
		sort(edge,edge+num);		
		//准备离散化 
		sort(Y,Y+num);
		num=unique(Y,Y+num)-Y; 
		int ans=0;
		for(int i=0;i<N*2;i++)
		{
			int low=lower_bound(Y,Y+num,edge[i].low)-Y;
			int high=lower_bound(Y,Y+num,edge[i].high)-Y;
			update(low,high,1,0,num,edge[i].c);//更新线段树 
			ans=max(ans,tree[1].max);//求最大权值 
		} 
		cout<<ans<<endl;
	}
	return 0;	
} 

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值