poj 2482 Stars in Your Window 线段树

传送门:poj 2482

好长的题目,结果前面的情书都可以不看,简单来说就是求给定大小的矩形中能包含到的星星的亮度的最大值,在矩形左边沿与下边沿的星星可行,上边沿与右边沿的不算


想了好久好久,在搜了题解之后总算是弄明白了

这里运用到了转化的思想,将每个点分别转化成为两条线段,线段有个权值,利用线段对线段树进行成段更新。每个星星的x坐标用来排序,记录添加线段的顺序,每个星星分出两条线段,一条x,更新的值为val,即星星的亮度一条x+w,更新的值为-val。每条线段更新的长度为从y到y+h-1,这里的x,y的值很大,因此需要对所有可能出现的y值进行离散化处理。最终在更新线段树的过程中,记录当前可能得到的最大值,即为最后的结果

/******************************************************
 * File Name:   2482.cpp
 * Author:      kojimai
 * Create Time: 2014年11月24日 星期一 16时56分49秒
 ******************************************************/

#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<iostream>
using namespace std;
#define FFF 23333
long long y[FFF];
struct node
{
	long long x,c,y1,y2;
}p[FFF];
bool cmp(node a,node b) {
	if(a.x == b.x)
		return a.c < b.c;
	return a.x < b.x;
}
struct nod {
	long long l,r;
	long long sum,down;
}pp[FFF*4];

void build(long long l,long long r,int num) {
	pp[num].l = l; pp[num].r = r; pp[num].sum = 0; pp[num].down = 0;
	if(l == r)
		return;
	int mid = (l + r) >> 1;
	build(l,mid,num*2);
	build(mid+1,r,num*2+1);
}

void solve(int num,long long val)
{
	pp[num*2].sum += val;
	pp[num*2].down += val;
	pp[num*2+1].sum += val;
	pp[num*2+1].down += val;
	pp[num].down = 0;
}
long long update(long long left,long long right,long long c,int num) {
	//cout<<" left = "<<left<<" right = "<<right<<" c = "<<c<<" num = "<<num<<" l = "<<pp[num].l<<" r = "<<pp[num].r<<endl;
	if(left == y[pp[num].l] && right == y[pp[num].r]) {
		pp[num].sum += c;
		pp[num].down += c;
		//cout<<" num = "<<num<<" sum = "<<pp[num].sum<<endl;
		return pp[num].sum;
	}
	if(pp[num].l == pp[num].r) {
		return pp[num].sum;
	}
	if(pp[num].down != 0)
		solve(num,pp[num].down);
	int mid = (pp[num].l + pp[num].r) >> 1;
	if(y[mid] >= right)
		pp[num].sum = max(update(left,right,c,num*2),pp[num*2+1].sum);
	else if(y[mid] < left)
		pp[num].sum = max(pp[num*2].sum,update(left,right,c,num*2+1));
	else
		pp[num].sum = max(update(left,y[mid],c,num*2),update(y[mid+1],right,c,num*2+1));
	//	cout<<" num = "<<num<<" sum = "<<pp[num].sum<<endl;
	return pp[num].sum;
}

int main()
{
	long long n,w,h;
	while(cin>>n>>w>>h)
	{
		for(long long i = 0;i < n;i++)
		{
			cin>>p[i*2].x>>p[i*2].y1>>p[i*2].c;
			y[i*2+1] = p[i*2].y1; y[i*2+2] = p[i*2].y1 + h - 1;
			p[i*2].y2 = p[i*2].y1 + h - 1;
			p[i*2+1].x = p[i*2].x + w;
			p[i*2+1].y1 = p[i*2].y1;
			p[i*2+1].y2 = p[i*2].y2;
			p[i*2+1].c = -p[i*2].c;
		}
		sort(y+1,y+2*n+1);
		sort(p,p+2*n,cmp);
		int cnt = unique(y+1,y+2*n+1)-y-1;
		build(1,cnt,1);

		long long ans = 0,t;
		for(int i = 0;i < 2*n;i++) {
			//cout<<"x1 = "<<p[i].x<<' ';
			//cout<<"y1 = "<<p[i].y1<<" y2 = "<<p[i].y2<<" c = "<<p[i].c<<endl;
			t = update(p[i].y1,p[i].y2,p[i].c,1);
			//cout<<" t = "<<t<<endl;
			ans = max(t,ans);
		}
		cout<<ans<<endl;;
	}
	return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值