首页 > 其他分享 >P1502 窗口的星星

P1502 窗口的星星

时间:2022-09-07 17:58:37浏览次数:89  
标签:星星 P1502 窗口 int LL 矩阵 long

目录

题目描述

平面上有n个有权点,有一个矩阵能框住最大的和,详情请看题面

分析

首先,我们考虑如何知道两颗星星可以在同一窗户内。
显然,我们可以直接判断,但你发现这做不出来。
我们可以将每个星星对应一个矩阵,若两个矩阵有重叠则这两个星星可以在一个窗口。

这样就可以将问题转换为:平面上有若干个矩形,每个矩形都带有一个权值,求在哪个坐标上权值的总和最大。
然后,跑一遍扫描线就可以了。
注意:小卡买的窗户框是金属做的,所以在边框上的不算在内。所以要减一。

代码

#include<bits/stdc++.h>
#define LL long long
using namespace std;
const int N=1e4+10;
int T,n,w,h;
LL a[N << 1];
struct Tree
{
	int l,r;
	LL maxn,add;
}t[N<<3];
struct node
{
	int x,y,h,l;
	bool operator<(const node &a)const
	{
		return (h!=a.h)?h<a.h:l>a.l;
	}
}p[N<<1];
void build(int p,int l,int r)
{
	t[p].l=l,t[p].r=r,t[p].maxn=t[p].add=0;
	if(l==r)return ;
	int mid=(l+r)>>1;
	build(p<<1,l,mid);
	build(p<<1|1,mid+1,r);
}
void pushdown(int p)
{
	t[p<<1].maxn+=t[p].add,t[p<<1|1].add+=t[p].add;
	t[p<<1|1].maxn+=t[p].add,t[p<<1].add+=t[p].add;
	t[p].add=0;
}
void add(int p,int x,int y,int k)
{
	int l=t[p].l,r=t[p].r;
	if(x<=l&&r<=y)
	{
		t[p].maxn+=k,t[p].add+=k;
		return ;
	}
	pushdown(p);
	int mid=(l+r)>>1;
	if(x<=mid)add(p<<1,x,y,k);
	if(y>mid)add(p<<1|1,x,y,k);
	t[p].maxn=max(t[p<<1].maxn,t[p<<1|1].maxn);
}
int main()
{
	scanf("%lld",&T);
	while(T--)
	{
		scanf("%d%d%d",&n,&w,&h);
		for(int i=1,x,y,l;i<=n;i++)
		{
			scanf("%d%d%d",&x,&y,&l);
			a[(i<<1)-1]=y,a[(i<<1)]=y+h-1;
			p[(i<<1)-1]=node{y,y+h-1,x,l};
			p[(i<<1)]=node{y,y+h-1,x+w-1,-l};
		}
		n<<=1;
		sort(a+1,a+n+1);
		sort(p+1,p+n+1);
		int cnt=unique(a+1,a+n+1)-a-1;
		for(int i=1;i<=n;i++)
		{
			p[i].x=lower_bound(a+1,a+cnt+1,p[i].x)-a;
			p[i].y=lower_bound(a+1,a+cnt+1,p[i].y)-a;
		}
		build(1,1,cnt);
		LL ans=0;
		for(int i=1;i<=n;i++)
		{
			add(1,p[i].x,p[i].y,p[i].l);
			ans=max(ans,t[1].maxn);
		}
		cout<<ans<<endl;
	}
}

标签:星星,P1502,窗口,int,LL,矩阵,long
From: https://www.cnblogs.com/gdfzlcx/p/16666666.html

相关文章