poj2482 Stars in Your Window hdu 5091 Beam Cannon 线段树 扫描线

今天终于把poj2482过了,然后把弱化版的2482 hdu5091用2482的代码随便改改也过了。就分析一下这两道题的相似和不同之处的处理。

poj2482该如何做,题意是让我们找到一个高为h,宽为w的矩形 包含最大的星星亮度。如果想找到这样的矩形,是很难的。但是换个思路,我们可以把星星所在的点扩展为以星星为中点的高为h,宽为w的矩形,然后我们的目标就是找到平面里的某个点 包含矩阵的数目最多。这样的问题就容易处理了。

我们把二维的平面通过扫描线转化为1维的区间处理问题。我们把每个矩形拆成2条竖线,然后按照x坐标排序,从左到右扫一遍。然后用线段树维护y坐标区间的最大值,遇到左边的线就把区间[y1 y2] 加上星星的亮度,遇到右线就减掉。然后用一个变量找到最大的亮度。

值得一提的是矩形是不包括边上的星星的。于是我们排序扫描线的时候要注意 如果x坐标相同就优先让右边的线先出去。还有就是我们维护的线段树维护的是线段 而不是 点段。

何为线段就是[0,2]中的0,2代表的是区间的端点,而这个线段包含0-1, 1-2 这2个点。而点段[0, 2] 指的是 0 , 1 ,2 这三个点。所以当我们遇到线段区间[0,2] 加 a和 [2,4] 加 b的时候,我们计算的结果是max(a,b),而不是a+b。注意线段的线段树和点段的线段树递归的时候边界处理稍微有点不同,对了,还有一点, 由于 x,y < 2^31,所以要对坐标离散化。离散化后二分也可以,或者直接把数组带入树内操作。详见代码。

而显然5091就是弱化版的 2482,第一,坐标区间是-20000 - 20000,不用离散化就可以直接建线段树。第二 每个点没有 所谓的亮度, 即每个点亮度为1。 第三 包含边框,所以在我们说到扫描线的排序的时候,相同x坐标的先加入左线 后加入右线。 线段树 用点段形式的。

额,由于5091的代码是改自 2482,故有些粗糙。 离散化的代码没删。然后也没把long long 改成int,看个思路即可。

poj2482代码:

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
const int N = 10009;
#define lson rt<<1
#define rson rt<<1|1
typedef long long LL;
struct Line{
    LL x,d,u;
    int c;
}line[N<<1];
struct Node{
    int add,ma;
}node[N<<3];
LL yy[N<<1];
void addline(int i, LL x, LL d, LL u, int c){
    line[i].x = x; line[i].d = d; line[i].u = u; line[i].c = c;
}
bool cmp(const Line &a, const Line &b){
    return a.x < b.x || a.x == b.x && a.c < b.c;
}
void inline change(int rt, int c){
    node[rt].add += c;
    node[rt].ma += c;
}
void inline push_down(int rt){
    if(node[rt].add){
        change(lson,node[rt].add);
        change(rson,node[rt].add);
        node[rt].add = 0;
    }
}
void inline push_up(int rt){
    node[rt].ma = max(node[lson].ma, node[rson].ma);
}
void update(int rt, int l, int r, LL L, LL R, int c){
    if(L <= yy[l] && R >= yy[r]){
        change(rt, c);
    }else{
        push_down(rt);
        int mid = l+r>>1;
        if(yy[mid] > L) update(lson, l, mid, L, R, c);
        if(yy[mid] < R) update(rson, mid, r, L, R, c);
        push_up(rt);
    }
}
int main(){
    int n,w,h;
    while(scanf("%d%d%d", &n, &w, &h) == 3){
        LL x,y;
        int c;
        for(int i = 0; i < n; i++){
            scanf("%lld%lld%d", &x, &y, &c);
            x <<= 1; y <<= 1;
            addline(i, x-w, y-h, y+h, c);
            addline(i+n, x+w, y-h, y+h, -c);
            yy[i] = y-h;yy[i+n] = y+h;
        }
        sort(yy, yy + 2*n);
        int m = unique(yy, yy + 2*n) - yy;
        sort(line, line+2*n, cmp);
        memset(node, 0, sizeof(node));
        int ma = -1;
        for(int i = 0; i < 2*n; i++){
          //  int u = lower_bound(yy, yy + m, line[i].u)- yy;
          //  int d = lower_bound(yy, yy + m, line[i].d)- yy;
           // printf("%d %d %d %d\n",line[i].x,d,u,line[i].c);
            update(1, 0, m-1, line[i].d, line[i].u, line[i].c);
            ma = max(ma, node[1].ma);
           // printf("%d\n", node[1].ma);
        }
        printf("%d\n", ma);
    }
    return 0;
}
hdu 5091:

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
const int N = 10009;
#define lson rt<<1
#define rson rt<<1|1
typedef long long LL;
struct Line{
    LL x,d,u;
    int c;
}line[N<<1];
struct Node{
    int add,ma;
}node[N<<3];
LL yy[N<<1];
inline void addline(int i, LL x, LL d, LL u, int c){
    line[i].x = x; line[i].d = d; line[i].u = u; line[i].c = c;
}
bool cmp(const Line &a, const Line &b){
    return a.x < b.x || a.x == b.x && a.c > b.c;
}
void inline change(int rt, int c){
    node[rt].add += c;
    node[rt].ma += c;
}
void inline push_down(int rt){
    if(node[rt].add){
        change(lson,node[rt].add);
        change(rson,node[rt].add);
        node[rt].add = 0;
    }
}
void inline push_up(int rt){
    node[rt].ma = max(node[lson].ma, node[rson].ma);
}
void update(int rt, int l, int r, LL L, LL R, int c){
    if(L <= yy[l] && R >= yy[r]){
        change(rt, c);
    }else{
        push_down(rt);
        int mid = l+r>>1;
        if(yy[mid] >= L) update(lson, l, mid, L, R, c);
        if(yy[mid] < R) update(rson, mid+1, r, L, R, c);
        push_up(rt);
    }
}
int main(){
    int n,w,h;
    while(scanf("%d", &n), n != -1){
        scanf("%d%d", &w, &h);
        LL x,y;
        int c = 1;
        for(int i = 0; i < n; i++){
            scanf("%I64d%I64d", &x, &y);
            x <<= 1; y <<= 1;
            addline(i, x-w, y-h, y+h, c);
            addline(i+n, x+w, y-h, y+h, -c);
            yy[i] = y-h;yy[i+n] = y+h;
        }
        sort(yy, yy + 2*n);
        int m = unique(yy, yy + 2*n) - yy;
        sort(line, line+2*n, cmp);
        memset(node, 0, sizeof(node));
        int ma = -1;
        for(int i = 0; i < 2*n; i++){
          //  int u = lower_bound(yy, yy + m, line[i].u)- yy;
          //  int d = lower_bound(yy, yy + m, line[i].d)- yy;
           // printf("%d %d %d %d\n",line[i].x,d,u,line[i].c);
            update(1, 0, m-1, line[i].d, line[i].u, line[i].c);
            ma = max(ma, node[1].ma);
           // printf("%d\n", node[1].ma);
        }
        printf("%d\n", ma);
    }
    return 0;
}


评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值