洛谷 P1502 窗口的星星 解题报告

P1502 窗口的星星

题目背景

小卡买到了一套新房子,他十分的高兴,在房间里转来转去。

题目描述

晚上,小卡从阳台望出去,“哇~~~~好多星星啊”,但他还没给其他房间设一个窗户,天真的小卡总是希望能够在晚上能看到最多最亮的星星,但是窗子的大小是固定的,边也必须和地面平行。这时小卡使用了超能力(透视术)知道了墙后面每个星星的位置和亮度,但是小卡发动超能力后就很疲劳,只好拜托你告诉他最多能够有总和多亮的星星能出现在窗口上。

输入输出格式

输入格式:

本题有多组数据,第一行为\(T\)表示有T组数据\(T \le 10\)

对于每组数据

第一行\(3\)个整数\(n\)\(W\)\(H\)\((n \le 10000,1 \le W,H \le 1000000)\) 表示有 \(n\) 颗星星,窗口宽为 \(W\),高为 \(H\)

接下来\(n\)行,每行三个整数 \(x_i\)\(y_i\)\(l_i\) 表示星星的坐标在\((x_i,y_i)\),亮度为\(l_i\)\((0 \le l_i,x_i,y_i<2^{31})\)

输出格式:

\(T\)个整数,表示每组数据中窗口星星亮度总和的最大值。

说明

小卡买的窗户框是金属做的,所以在边框上的不算在内。


说明的意思等价于把\(w--,h--\)然后做闭区间,不是\(-=2\)的原因是窗口可以不在整数点上

我们把矩形左上角视为矩形的位置,然后对每个星星,我们都有一个区域满足当矩形落在这个区域时,可以得到这个星星的亮度

也就是我们在所有星星的区域构成的集合中取一点得到最大的亮度之和

可以拿扫描线维护这个操作,要求维护区间加和全局最大值

因为是第一次写扫描线,所以犯了一个错误供大家借鉴借鉴

对扫描线多元组排序时,若\(x\)坐标相等时,先执行撤销操作(如果是对每个点先操作再询问的话)


Code:

#include <cstdio>
#include <algorithm>
#include <map>
#include <cstring>
using namespace std;
const int N=2e4+10;
map <int,int > dx,dy;
int px[N],py[N],shine[N],n,m,w,h,nx,ny;
struct node
{
    int x,up,dow,shine;
    bool friend operator <(node n1,node n2)
    {
        return n1.x==n2.x?n1.shine<n2.shine:n1.x<n2.x;
    }
}line[N];
void init()
{
    dx.clear(),dy.clear();
    scanf("%d%d%d",&n,&w,&h);//个数、长、宽
    --w,--h;
    for(int i=1;i<=n;i++)
    {
        scanf("%d%d%d",px+i,py+i,shine+i);
        dx[px[i]]=1,dy[py[i]]=1;
        dx[px[i]-w]=1,dy[py[i]-h]=1;
    }
    nx=0,ny=0;
    for(map <int,int >::iterator it=dx.begin();it!=dx.end();it++)
        it->second=++nx;
    for(map <int,int >::iterator it=dy.begin();it!=dy.end();it++)
        it->second=++ny;
    m=0;
    for(int i=1;i<=n;i++)
    {
        line[++m]={dx[px[i]]+1,dy[py[i]-h],dy[py[i]],-shine[i]};
        line[++m]={dx[px[i]-w],dy[py[i]-h],dy[py[i]],shine[i]};
    }
    sort(line+1,line+1+m);
}
int lazy[N<<2],mx[N<<2];
#define ls id<<1
#define rs id<<1|1
void pushdown(int id)
{
    if(lazy[id])
    {
        lazy[ls]+=lazy[id],lazy[rs]+=lazy[id];
        mx[ls]+=lazy[id],mx[rs]+=lazy[id];
        lazy[id]=0;
    }
}
void updata(int id)
{
    mx[id]=max(mx[ls],mx[rs]);
}
void change(int id,int l,int r,int L,int R,int delta)
{
    if(l==L&&r==R)
    {
        lazy[id]+=delta;
        mx[id]+=delta;
        return;
    }
    pushdown(id);
    int Mid=L+R>>1;
    if(r<=Mid) change(ls,l,r,L,Mid,delta);
    else if(l>Mid) change(rs,l,r,Mid+1,R,delta);
    else change(ls,l,Mid,L,Mid,delta),change(rs,Mid+1,r,Mid+1,R,delta);
    updata(id);
}
void work()
{
    memset(mx,0,sizeof(mx));
    memset(lazy,0,sizeof(lazy));
    int ans=0;
    for(int i=1;i<=m;i++)
    {
        change(1,line[i].up,line[i].dow,1,ny,line[i].shine);
        ans=max(ans,mx[1]);
    }
    printf("%d\n",ans);
}
int main()
{
    int t;scanf("%d\n",&t);
    while(t--)
        init(),work();
    return 0;
}


2018.8.31

posted @ 2018-08-31 10:20  露迭月  阅读(265)  评论(0编辑  收藏  举报