Stars in Your Window

Stars in Your Window

https://ac.nowcoder.com/acm/problem/107079

题意:
在一个天空中有颗星星(看作平面直角坐标系),已知每颗星星的坐标和亮度(都是整数)。求用宽为、高为的矩形(都是整数)能圈住的星星的亮度总和最大是多少(矩形边界上的星星不算)。 应该是不大于

思路:

因为矩阵大小固定,所以矩形可以由它的任一顶点确定。我们可以考虑把矩形的右上角顶点放在什么位置,圈住的星星亮度最大。
对一个星星,能圈住它的矩形右上角的顶点范围是:在左下角顶点为,右上角顶点为的矩形内,不包括边界上的点。这里用区域代指这个范围。

“矩形边界上的星星不算”,这个边界需要处理一下。因为星星的坐标都是整数,所以矩形右上角的顶点的结果都是一样的,那么我可以区域是:在左下角顶点为,右上角顶点为的矩形内,包括边界上的点。如果我把星星的坐标往左下移呢,那么区域变成:在左下角顶点为,右上角顶点为的矩形内,包括边界上的点,区域内点的坐标都是整数即可!

此时,问题转化为:平面上有若干个区域,每个区域都带有一个权值,求在那个坐标上重叠的区域权值最大。其中,每一个区域都是由一颗星星产生的,权值等于星星的亮度,把原问题中的矩形右上角放在该区域中就能圈住这颗星星。

问题转化后就可以使用扫描线算法,取每个区域的左右边界,保存成两个四元组。把这些四元组按照横坐标排序。扫描线就是类似差分的思想,以横坐标为转移,把纵坐标的区间权值并起来。区域的右上角顶点是,而另一个四元组为,就相当于给你一个数组,要在区间加上值,那么差分的操作就是,然后用前缀和就可以得到修改后的数组,而扫描线就相当于一个求前缀和的过程。

将纵坐标的区间权值并起来可以用到线段树,只涉及区间修改,同时维护区间最大值,需要懒标记。
考虑到比较大,但是四元组中的纵坐标最多只有个,先离散化。

MyCode:

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <cstdlib>
#include <cctype>
#include <string>
#include <iostream>
#include <vector>
#include <map>
#include <set>
#include <stack>
#include <queue>
using namespace std;
const int maxn=2e4+7,maxE=8e4+7;
typedef long long int ll;
struct node {
    ll x,l,r,val;
    bool operator<(const node& a)const {
        return x<a.x;
    }
} q[maxn];
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
ll lazy[maxE],tree[maxE];
inline ll max(ll a,ll b) {
    return a>b?a:b;
}
inline void pushdown(int rt) {
    if(lazy[rt]) {
        lazy[rt<<1]+=lazy[rt];
        lazy[rt<<1|1]+=lazy[rt];
        tree[rt<<1]+=lazy[rt];
        tree[rt<<1|1]+=lazy[rt];
        lazy[rt]=0;
    }
}
inline void update(int x,int y,ll val,int l,int r,int rt) {
    if(x<=l&&r<=y) {
        lazy[rt]+=val;
        tree[rt]+=val;
        return;
    }
    pushdown(rt);
    int mid=(l+r)>>1;
    if(x<=mid) update(x,y,val,lson);
    if(y>mid) update(x,y,val,rson);
    tree[rt]=max(tree[rt<<1],tree[rt<<1|1]);
}
ll b[maxn];
int main() {
    int n,w,h,tot=0;
    while(~scanf("%d%d%d",&n,&w,&h)) {
        tot=0;
        memset(lazy,0,sizeof lazy);
        memset(tree,0,sizeof tree);
        for(ll i=0,x,y,c; i<n; ++i) {
            scanf("%lld%lld%lld",&x,&y,&c);
            q[++tot]=node {x,y,y+h-1,c};
            b[tot]=y;
            q[++tot]=node {x+w,y,y+h-1,-c};
            b[tot]=y+h-1;
        }
        sort(b+1,b+1+tot);
        int mm=unique(b+1,b+1+tot)-b;
        for(int i=1; i<=tot; i+=2) {
            q[i].l=q[i+1].l=lower_bound(b+1,b+mm,q[i].l)-b;
            q[i].r=q[i+1].r=lower_bound(b+1,b+mm,q[i].r)-b;
        }
        sort(q+1,q+1+tot);
        ll ans=0;
        mm-=1;
        for(int i=1; i<=tot; ++i) {
            update(q[i].l,q[i].r,q[i].val,1,mm,1);
            if(q[i].val>0)
                ans=max(ans,tree[1]);
        }
        printf("%lld\n",ans);
    }
    return 0;
}
线段树进阶 文章被收录于专栏

NULL

全部评论

相关推荐

老粉都知道小猪猪我很久没更新了,因为秋招非常非常不顺利,emo了三个月了,接下来说一下我的情况吧本人是双非本&nbsp;专业是完全不着计算机边的非科班,比较有优势的是有两段大厂实习,美团和字节。秋招面了50+场泡池子泡死的:滴滴&nbsp;快手&nbsp;去哪儿&nbsp;小鹏汽车&nbsp;不知名的一两个小厂其中字节13场&nbsp;两次3面挂&nbsp;两次2面挂&nbsp;一次一面挂其中有2场面试题没写出来,其他的都是全a,但该挂还是挂,第三次三面才面进去字节,秋招加暑期总共面了22次字节,在字节的面评可以出成书了快手面了8场,2次实习的,通过了但没去,一次2面挂&nbsp;最后一次到录用评估&nbsp;至今无消息滴滴三面完&nbsp;没几天挂了&nbsp;所有技术面找不出2个问题是我回答不上来的,三面还来说我去过字节,应该不会考虑滴滴吧,直接给我干傻了去哪儿一天速通&nbsp;至今无消息小鹏汽车hr&nbsp;至今无消息美团2面挂&nbsp;然后不捞我了,三个志愿全部结束,估计被卡学历了虾皮二面挂&nbsp;这个是我菜,面试官太牛逼了拼多多二面挂&nbsp;3道题也全写了&nbsp;也没问题是回答不出来的&nbsp;泡一周后挂腾讯面了5次&nbsp;一次2面挂&nbsp;三次一面挂,我宣布腾讯是世界上最难进的互联网公司然后还有一些零零散散的中小厂,但是数量比较少,约面大多数都是大厂。整体的战况非常惨烈,面试机会少,就算面过了也需要和各路神仙横向对比,很多次我都是那个被比下去的人,不过这也正常,毕竟谁会放着一个985的硕士不招,反而去招一个双非读化学的小子感觉现在互联网对学历的要求越来越高了,不仅仅要985还要硕士了,双非几乎没啥生存空间了,我感觉未来几年双非想要进大厂开发的难度应该直线上升了,唯一的打法还是从大二刷实习,然后苟个转正,不然要是去秋招大概率是炮灰。而且就我面字节这么多次,已经开始问很多ai的东西了,你一破本科生要是没实习没科研懂什么ai啊,纯纯白给了
不知名牛友_:爸爸
秋招你被哪家公司挂了?
点赞 评论 收藏
分享
评论
1
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务