【Luogu P1502】窗口的星星

Luogu P1502

题意很好理解,就是问给出的矩形套住的最大和。

但是做起来却十分麻烦。


——来自疯狂爆10分的愤怒

一个比较高效的思路是——把每一个星星作为左下角向右上方拓展形成一个矩形,
拓展的规则为只要窗口的右上角在这个矩形之内,就可以覆盖到这个星星。然后用线段树维护一条扫描线从左往右扫过去,寻找单点的最大值。

值得注意的是题面提出了窗框上的星星不计入答案,这样一搞整道题就变得相当恶心了

一个比较好理解且比较方便的做法就是以星星的横纵坐标+0.5作为矩形的左下角。

那么这样就能保证这个矩形符合拓展的规则了。

另外,由于星星的坐标很大,可以使用离散化缩小范围

code time:

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#define lson root<<1
#define rson root<<1|1
#define ll long long
using namespace std;
struct data
{
    double l,r,x;
    ll flag;
}line[80005];
bool cmp(data a,data b)
{
    if (a.x==b.x) return a.flag<b.flag;
    return a.x<b.x;
    //重点之一,注意权值小的排在前面,因为在矩形的右边界上,这颗星星已经对答案没有贡献了
}
ll tag[80005],tree[80005],n,w,h,x,y,l,cnt,ans,T;
double pnt[80005];
void push_down(ll root,ll l,ll r)
{
    tag[lson]+=tag[root];
    tag[rson]+=tag[root];
    tree[lson]+=tag[root];
    tree[rson]+=tag[root];
    tag[root]=0;    
}*/
void update(ll root,ll l,ll r,double L,double R,ll flag)
{
    if (L<=pnt[l]&&pnt[r]<=R)
    {
        tag[root]+=flag;
        tree[root]+=flag;
        return ;
    }
    if (l+1==r) return ;
    if (R<=pnt[l]||L>=pnt[r]) return ;
    push_down(root,l,r);
    //事实上不需要pd操作也能过。
    ll mid=(l+r)>>1;
    if (L<pnt[mid]) update(lson,l,mid,L,R,flag);
    if (R>pnt[mid]) update(rson,mid,r,L,R,flag);
    //注意离散化后mid仅为下标,而不是坐标。
    tree[root]=max(tree[lson],tree[rson])+tag[root];
}
int main()
{
    scanf("%d",&T);
    for (int q=1;q<=T;q++)
    {
        cnt=0;
        ans=0;
        memset(line,0,sizeof(line));
        memset(pnt,0,sizeof(pnt));
        memset(tree,0,sizeof(tree));
        memset(tag,0,sizeof(tag));
        //记得要初始化
        scanf("%d%d%d",&n,&w,&h);
        for (int i=1;i<=n;i++)
        {
            scanf("%d%d%d",&x,&y,&l);
            line[++cnt].x=x+0.5;line[cnt].l=y+0.5;line[cnt].r=y+h;line[cnt].flag=l;pnt[cnt]=y+h;
            line[++cnt].x=x+w;line[cnt].l=y+0.5;line[cnt].r=y+h;line[cnt].flag=-l;pnt[cnt]=y+0.5;
            //重点之一,对边界的处理
        }
        sort(line+1,line+1+cnt,cmp);
        sort(pnt+1,pnt+1+cnt);
        ll til=unique(pnt+1,pnt+1+cnt)-pnt-1;
        for (int i=1;i<=cnt;i++)
        {
            update(1,1ll,til,line[i].l,line[i].r,line[i].flag);
            ans=max(ans,tree[1]);
        }
        printf("%lld\n",ans);
    }
    return 0;
}
posted @ 2019-11-02 18:04  Nanjo  阅读(179)  评论(0编辑  收藏  举报