POJ_2482_Stars in Your Window_线段树、离散化处理

手机屏摔碎了哦凑。

题意

一个平面里有N(N<10000)个点,每个点 有一个值Vi,用一个长宽为W,H的矩形框,在平面内平移,不能旋转,最多能使框内(不包括边界)的点的V值和为多少 ?

IO

Input
There are several test cases in the input. The first line of each case contains 3 integers: n, W, H, indicating the number of stars, the horizontal length and the vertical height of the rectangle-shaped window. Then n lines follow, with 3 integers each: x, y, c, telling the location (x, y) and the brightness of each star. No two stars are on the same point.

There are at least 1 and at most 10000 stars in the sky. 1<=W,H<=1000000, 0<=x,y<2^31.

Output
For each test case, output the maximum brightness in a single line.

分析

首先要对问题进行一次转化,对每个点来说,矩形框中心的位置必须在以当前点为中心的一个w,h的矩形框内,那么我们就可以把点转化为矩形,而把矩形转化为点。
之所以要进行这样的转化,是因为我们要移动矩形,而点是不动的,显然矩形这一模型比点要复杂,因此我们把静态的点转化为更复杂的矩形,而把动态的矩形转化为简单的点。
用一条扫描线的从左往右扫,维护沿y轴方向矩形数量的分布信息,注意对于转化后的问题,扫描线进入一个矩形以后,分布信息中就应在对应位置加上它,知道出这个矩形,删除对应信息。用线段树来维护当前沿y轴矩形数量分布信息。
实现会遇到一些小问题:
从左到右的距离太大——排序矩形的左右边,扫描矩形左右边。
纵向距离太大——离散化纵向座标。
按照题意点在框上的情况不算——由于输入都是整数,用一个小于0.5的小数修正即可。

代码

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
#define MXN 10010
int ll[MXN<<4],rr[MXN<<4],sum[MXN<<4],flag[MXN<<4];
int n,w,h;
int ans;
void build(int id,int l,int r){
    ll[id]=l,rr[id]=r,sum[id]=flag[id]=0;
    int m=(l+r)>>1,ls=id<<1,rs=ls|1;
    if(l!=r){
        build(ls,l,m);
        build(rs,m+1,r);
    }
}
struct line{
    double x,l,h,v;
    bool end;
    line(){}
    line(double a,double b,double c,long long e,bool d){x=a,l=b,h=c,end=d,v=e;}
    bool operator < (const line& rgt)const{
        return x<rgt.x||x==rgt.x&&end;
    }
}l[MXN<<2];
long long lcnt,tot;
double dy[MXN<<2];
void input(){
    ans=lcnt=tot=0;
    for(int i=0;i<n;++i){
        int tx,ty,tc;
        scanf("%d%d%d",&tx,&ty,&tc);
        double tl=ty-h/2.0+0.1;
        double th=ty+h/2.0-0.1;
        double ttx=tx-w/2.0+0.1;
        l[lcnt++]=line(ttx,tl,th,tc,false);
        ttx=tx+w/2.0-0.1;
        l[lcnt++]=line(ttx,tl,th,tc,true);
        dy[tot++]=tl;
        dy[tot++]=th;
    }
    sort(l,l+lcnt);
    sort(dy,dy+tot);
    tot=unique(dy,dy+tot)-dy;
}
void down(int id);
void add(int id,double l,double r,int v,bool end){
    if(flag[id])    down(id);
    if(l==dy[ll[id]]&&r==dy[rr[id]]){
        flag[id]+=end ? -v : v;
        sum[id]+=flag[id];
        return;
    }
    int m=(ll[id]+rr[id])>>1,ls=id<<1,rs=ls|1;
    if(r<=dy[m])    add(ls,l,r,v,end);
    else if(l>dy[m])    add(rs,l,r,v,end);
    else{
        add(ls,l,dy[m],v,end);
        add(rs,dy[m+1],r,v,end);
    }
    sum[id]=max(sum[ls],sum[rs]);
}
void down(int id){
    if(ll[id]==rr[id]){
        flag[id]=0;
        return;
    }
    int m=(ll[id]+rr[id])>>1,ls=id<<1,rs=ls|1;
    add(ls,dy[ll[id]],dy[m],abs(flag[id]),flag[id]<0);
    add(rs,dy[m+1],dy[rr[id]],abs(flag[id]),flag[id]<0);
    flag[id]=0;
}
int query(int id){
    if(flag[id]){
        down(id);
    }
    return sum[id];
}
void solve(){
    for(int i=0;i<lcnt;++i){
        add(1,l[i].l,l[i].h,l[i].v,l[i].end);
        ans=max(query(1),ans);
    }
}
int main(){
    //freopen("data.txt","r",stdin);
    //freopen("ans.txt","w",stdout);
    while(scanf("%d%d%d",&n,&w,&h)!=EOF){
        input();
        build(1,0,tot-1);
        solve();
        printf("%d\n",ans);
    }
    return 0;
}
点赞