首页 > 其他 > 详细

【题解】窗口的星星

时间:2019-09-05 21:25:31      阅读:100      评论:0      收藏:0      [点我收藏+]

前置芝士 扫描线

题目链接

题目大意就是,问窗口能框住的最大亮度。

转化一下题意,把每一颗星星扩展为一个长宽为\(H,W\)的矩形,在矩形里面,都是可以框住这颗星星的。

那么问题就转化为,求一些矩形的最大面积并。

显然扫描线做。线段树维护区间加的亮度,同时维护\(MAX\),查询的时候,一次次加边,一次次更新答案即可。

注意数据大,需要离散化。用\(sort,unique\)就很方便。

其中,我的\(LowerBound\)是手写的\(find\)函数。

\(Code:\)

#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
#define int long long
const int MAXN=5000000;
int T,n,tot,rec,val[MAXN];
int rk[MAXN],W,H,Ans,ans;
struct SegmentTree{
    int l,r,tag,v;
}tr[MAXN];
struct Line{
    int l,h,v,x;
    bool operator<(const Line&A)const{
        return h<A.h;
    }
}e[MAXN];
void build(int l,int r,int x){
    tr[x].l=l;
    tr[x].r=r;
    tr[x].tag=tr[x].v=0;
    if(l==r)return;
    int mid=l+r>>1;
    build(l,mid,x<<1);
    build(mid+1,r,x<<1|1);
}
inline void pushdown(int x){
    if(tr[x].tag){
        tr[x<<1].tag+=tr[x].tag;
        tr[x<<1|1].tag+=tr[x].tag;
        tr[x<<1].v+=tr[x].tag;
        tr[x<<1|1].v+=tr[x].tag;
        tr[x].tag=0;
    }
}
void change(int x,int l,int r,int k){
    if(tr[x].l>=l&&tr[x].r<=r){
        tr[x].tag+=k;
        tr[x].v+=k;
        pushdown(x);
        return;
    }
    pushdown(x);
    int mid=(tr[x].l+tr[x].r)>>1;
    if(l<=mid)change(x<<1,l,r,k);
    if(mid<r)change(x<<1|1,l,r,k);
    tr[x].v=max(tr[x<<1].v,tr[x<<1|1].v);
}
inline bool cmp(Line A,Line B){
    if(A.x==B.x)return A.v>B.v;
    else return A.x<B.x; 
}
int find(int x){
    int l=1,r=rec,A;
    while(l<=r){
        int mid=l+r>>1;
        if(rk[mid]==x)return mid;
        else if(rk[mid]>x)r=mid-1,A=r;
        else if(rk[mid]<x)l=mid+1,A=l;
    }
    return A;
}
void query(int x,int l,int r){
    if(tr[x].l>=l&&tr[x].r<=r){
        ans=max(ans,tr[x].v);
        return;
    }
    pushdown(x);
    int mid=tr[x].l+tr[x].r>>1;
    if(l<=mid)query(x<<1,l,r);
    if(mid<r)query(x<<1|1,l,r);
}
signed main(){
    scanf("%lld",&T);
    while(T--){
        n=W=H=0;
        tot=0,rec=0,Ans=0,ans=0;
        memset(val,0,sizeof(val));
        memset(rk,0,sizeof(rk));
        scanf("%lld%lld%lld",&n,&W,&H);
        for(int i=1,x,y,v;i<=n;++i){
            scanf("%lld%lld%lld",&x,&y,&v);
            int x1=x-W,y1=y-1,x2=x-1,y2=y-H;
            e[(i<<1)-1].x=x1,e[i<<1].x=x2;
            e[(i<<1)-1].h=e[i<<1].h=y2;
            e[(i<<1)-1].l=e[i<<1].l=y1;
            e[(i<<1)-1].v=v;e[i<<1].v=-v;
            rk[++tot]=y1,rk[++tot]=y2;
        }
        sort(rk+1,rk+tot+1);
        rec=unique(rk+1,rk+tot+1)-rk-1;
        for(int i=1;i<=(n<<1);++i){
            int pos1=find(e[i].h);
            int pos2=find(e[i].l);
            val[pos1]=e[i].h;
            val[pos2]=e[i].l;
            e[i].h=pos1;e[i].l=pos2;
        }
        sort(e+1,e+(n<<1|1),cmp);
        build(1,(n<<1),1); 
        for(int i=1;i<=(n<<1);++i){
            change(1,e[i].h,e[i].l,e[i].v);
            query(1,e[i].h,e[i].l);
            Ans=max(Ans,ans);
        }
        printf("%lld\n",Ans);
    }
    return 0;
}

有时间准备扫描线讲解,准备历史去\(QAQ\)

【题解】窗口的星星

原文:https://www.cnblogs.com/h-lka/p/11469841.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!