Luogu_1502 窗口的星星【题解】扫描线

题目链接:https://www.luogu.org/problem/P1502

其实一眼看不出扫描线。

我们可以把每一个点都变成一个长宽为w和h的矩形。

左边的边是+w,右边的边是-w。

线段树维护区间max和lazy tag。

然后扫描线求max。

代码如下:

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int maxn=20010;
int n,w,h,t,b[maxn<<1],tot;
struct node{
    ll mx,tag;
    #define mx(x) tree[x].mx
    #define tag(x) tree[x].tag
}tree[maxn<<2];
struct s{
    int x,yl,yh,fl;
    s(){}
    s(int xx,int yy1,int yy2,int ff){x=xx;yl=yy1;yh=yy2;fl=ff;}
}e[maxn<<1];
inline bool cmp(s x,s y){
    return x.x==y.x ? x.fl>y.fl : x.x<y.x;
}
inline void pushdown(int p,int l,int r){
    if(!tag(p)) return;
    mx(p)+=tag(p);
    if(l!=r){
        tag(p<<1)+=tag(p);
        tag(p<<1|1)+=tag(p);
    }
    tag(p)=0;
}
inline void add(int p,int l,int r,int x,int y,int d){
    if(x<=l&&r<=y){
        tag(p)+=d;return;
    }
    int mid=(l+r)>>1;
    if(x<=mid) add(p<<1,l,mid,x,y,d);
    if(y>mid) add(p<<1|1,mid+1,r,x,y,d);
    pushdown(p<<1,l,mid);
    pushdown(p<<1|1,mid+1,r);
    mx(p)=max(mx(p<<1),mx(p<<1|1));
}
int main()
{
    scanf("%d",&t);
    while(t--){
        memset(tree,0,sizeof(tree));
        tot=0;
        scanf("%d%d%d",&n,&w,&h);
        for(int i=1;i<=n;i++){
            int x,y,v;
            scanf("%d%d%d",&x,&y,&v);
            e[++tot].x=x;b[tot]=y;
            e[tot].yl=y;e[tot].yh=y+h-1;e[tot].fl=v;
            e[++tot].x=x+w-1;b[tot]=y+h-1;
            e[tot].yl=y;e[tot].yh=y+h-1;e[tot].fl=-v;
        }
        sort(b+1,b+1+2*n);
        tot=unique(b+1,b+1+2*n)-b-1;
        sort(e+1,e+1+2*n,cmp);
        ll ans=0;
        for(int i=1;i<=2*n;i++){
            int h1=lower_bound(b+1,b+1+tot,e[i].yh)-b;
            int h2=lower_bound(b+1,b+1+tot,e[i].yl)-b;
            e[i].yl=h2;e[i].yh=h1;
        }
        for(int i=1;i<=2*n;i++){
          add(1,1,2*n,e[i].yl,e[i].yh,e[i].fl);
          ans=max(ans,mx(1));
        }
        printf("%lld
",ans);
    }
    return 0;
}
原文地址:https://www.cnblogs.com/ChrisKKK/p/11493679.html