窗口的星星

 

 

第一次写题解啊~~~

luoguP1502 窗口的星星

一道很好(fan)的练习线段树+离散化+扫描线题

题目::https://www.luogu.org/problemnew/show/P1502

人话题意::在坐标系上有若干个点,每个点有不同的权值,求用一个W*H的矩形最多框住的值~~~~

很明显因为x,y为0到2^31肯定要离散化因为到时候要存结构体,所以手动离散,x和y分别离散

神奇思路::因为矩形有一个固定的长和宽, 所以我们可以将每个点可以被框入的范围视为一个矩形。 为了不重复计算 我们统一只计算向上及向右的矩形,

如图:

我们可以发现 矩形相交则说明有一个矩形可以把他们都框进去~~

之后按纵坐标排序,从下向上扫描;

若扫描到的边为矩形下边则将该边对应矩形的左右界上传到线段树中(线段树用于维护一段区间内最大的价值,如图中,1-2为valA,2-3为valB+valA,1-3为valA+valB,1-4为valA+valB+valC……);

若为上界,则反向上传

最后取max一下

就好了

然后按思路打好代码

```cpp

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
const int M=101000;
struct tr{
int sum,add;
}tree[M<<2];
int n,w,h,x[M],y[M],L[M],tot=0,lia[M],lib[M];
struct data{
int num,a;
int lis;
int type;
}ax[M<<2],ay[M<<2];
bool cmp1(data x,data y){
if(x.a==y.a) return x.type<y.type;//边相同时,上边排在前面(针对ay)
return x.a<y.a;
}
bool cmp2(data x,data y){
if(x.lis==y.lis) return x.a<y.a;
return x.lis<y.lis;
}
inline void build(int p,int l,int r)
{
tree[p].sum=0;
tree[p].add=0;//注意0!!
if(l==r){
return;
}
int mid=l+r>>1;
build(p<<1,l,mid);
build(p<<1|1,mid+1,r);
}
inline void spread(int p){
if(tree[p].add){
tree[p<<1].sum+=tree[p].add;
tree[p<<1|1].sum+=tree[p].add;
tree[p<<1].add+=tree[p].add;
tree[p<<1|1].add+=tree[p].add;
tree[p].add=0;
}
}
inline void add(int p,int l,int r,int posl,int posr,int x)
{
if(posl<=l&&posr>=r){
tree[p].sum+=x;
tree[p].add+=x;
return;
}
spread(p);
int mid=l+r>>1;
if(posl<=mid) add(p<<1,l,mid,posl,posr,x);
if(posr>mid) add(p<<1|1,mid+1,r,posl,posr,x);
tree[p].sum=max(tree[p<<1].sum,tree[p<<1|1].sum);
}
inline int query(int p,int l,int r,int ql,int qr)
{
if(ql<=l&&qr>=r)
{
return tree[p].sum;
}
spread(p);
int mid=l+r>>1;
int val=0;
if(ql<=mid) val=max(val,query(p<<1,l,mid,ql,qr));
if(qr>mid) val=max(val,query(p<<1|1,mid+1,r,ql,qr));
return val;
}
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
int ans=0;
tot=0;
scanf("%d%d%d",&n,&w,&h);
for(int i=1;i<=n;i++){
scanf("%d%d%d",&x[i],&y[i],&L[i]);
ax[++tot].a=x[i];ax[tot].num=i;ax[tot].type=1;
ay[tot].a=y[i];ay[tot].num=i;ay[tot].type=1;//type==1表示为下边,0为上边
ax[++tot].a=x[i]+w-1;ax[tot].num=i;ax[tot].type=0;
ay[tot].a=y[i]+h-1;ay[tot].num=i;ay[tot].type=0;
}
sort(ax+1,ax+1+tot,cmp1);
int cnt=tot;
for(int i=1;i<=tot;i++)
{
if(ax[i].a==ax[i-1].a&&i!=1)
ax[i].lis=0x7f7f7f7f,cnt--;
else ax[i].lis=0;
}//手动离散
sort(ax+1,ax+1+tot,cmp2);
for(int i=1;i<=cnt;i++) lia[i]=ax[i].a;
build(1,1,cnt);
sort(ay+1,ay+1+tot,cmp1);
for(int i=1;i<=tot;i++)
{
int l=lower_bound(lia+1,lia+1+cnt,x[ay[i].num])-lia,r=lower_bound(lia+1,lia+1+cnt,x[ay[i].num]+w-1)-lia;
if(ay[i].type){//扫描到下边
ans=max(ans,query(1,1,cnt,l,r)+L[ay[i].num]);//因为做的时候L[ay[i].num还没加过
}
if(ay[i].type)
add(1,1,cnt,l,r,L[ay[i].num]);
else add(1,1,cnt,l,r,-L[ay[i].num]); //加负值就等于删了。。。
}
cout<<ans<<endl;
}
}

```cpp

好的那么

提交;

大喊一声

然并卵WA了一个点

一看讨论版

为了AC果断放弃正解

改成
if(x.a==y.a) return x.type>y.type;

再交一遍

 哈哈哈哈哈哈哈结果你懂的

 

转载于:https://www.cnblogs.com/Cseller/p/9507132.html

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值