hdu1542 Atlantis

求矩形面积的并,这个题应该是线段树刚刚出现在竞赛时要做的题。

这个题的主要思想就是扫描,我们将所有矩形竖直方向的两条线段,都拿出来排序,然后扫描用线段树维护覆盖的线段长度即可。


对于如上的矩形给所有竖直线段排序后就可以得到下面的图


我们可以观察到从一条线段到下一条线段之前竖直方向的覆盖长度a都不变,而这两条线段之间的距离为b,那么这两条线段之间的面积表示为a * b。

邻近的两条竖直的线段将整个图形分解成若干个部分,我们按上面的方法计算的面积的和就是面积的并了。

为了快速得到竖直方向的覆盖情况,我们用线段树来维护。

比如上图,第一条线段覆盖了a1,到下一条线段的距离为b1,计算面积;第二条与第一条线段共同覆盖了a2,到下一条线段的距离为b2;第三条线段退出覆盖,覆盖的长度为a3(a3==a1),到下一线段的距离为b3....

那么总面积为a1 * b1 + a2 * b2 + a3 * b3 ...

就可以输出答案了。

代码很丑,慢慢看。

#include<cstdio>
#include<algorithm>
using namespace std;

struct node {
    double x, y;
};
struct edge {
    double x;
    int st, ed;
    int wt;
    bool operator < (const edge &rhs)   const   {
        return x < rhs.x;
    }
};

const int MAXN = 500;

int n;
node A[MAXN + 10], B[MAXN + 10];
int nn;
edge Edge[MAXN + 10];
int mx;
double val[MAXN + 10];

struct seg  {
    int l, r;
    int sig;
    double cnt;
    inline double length()  {   return val[r] - val[l]; }
    void update(seg &lch, seg &rch)   {
        if(sig) cnt = length();
        else {
            if(l + 1 >= r)  cnt = 0;
            else cnt = lch.cnt + rch.cnt;
        }
    }
}   Tree[MAXN * 4 + 10];

void Build(int u, int l, int r)    {
    seg &cur = Tree[u];
    cur.l = l, cur.r = r;
    cur.cnt = cur.sig = 0;
    if(l + 1 >= r)  return ;
    int mid = (l + r) / 2;
    Build(u * 2, l, mid);
    Build(u * 2 + 1, mid, r);
}
void Ins(int u, int l, int r, int x)  {
    seg &cur = Tree[u], &lch = Tree[u * 2], &rch = Tree[u * 2 + 1];
    if(cur.l >= r || cur.r <= l)    return ;
    else if(l <= cur.l && cur.r <= r)   cur.sig += x;
    else {
        Ins(u * 2, l, r, x);
        Ins(u * 2 + 1, l, r, x);
    }
    cur.update(lch, rch);
}
double work()   {
    mx = nn = 0;
    for(int i = 1; i <= n; i++) val[++mx] = A[i].y, val[++mx] = B[i].y;
    sort(val + 1, val + 1 + mx);
    mx = unique(val + 1, val + 1 + mx) - val - 1;
    for(int i = 1; i <= n; i++) {
        int y1 = lower_bound(val + 1, val + 1 + mx, A[i].y) - val, y2 = lower_bound(val + 1, val + 1 + mx, B[i].y) - val;
        Edge[++nn] = (edge){A[i].x, y1, y2, 1};
        Edge[++nn] = (edge){B[i].x, y1, y2, -1};
    }
    sort(Edge + 1, Edge + 1 + nn);

    double ans = 0;
    double Last = 0;

    Build(1, 1, mx);
    for(int i = 1; i <= nn; i++)    {
        if(i != 1)  ans += Tree[1].cnt * (Edge[i].x - Last);
        Last = Edge[i].x;
        Ins(1, Edge[i].st, Edge[i].ed, Edge[i].wt);
    }
    return ans;
}

int main()  {
    int kase = 0;
    while(scanf("%d", &n) == 1 && n)    {
        for(int i = 1; i <= n; i++) {
            scanf("%lf%lf", &A[i].x, &A[i].y);
            scanf("%lf%lf", &B[i].x, &B[i].y);
        }
        printf("Test case #%d\nTotal explored area: %.2f\n\n", ++kase, work());
    }
    return 0;
}

相应的我们也会求矩形面积的交、并、以及周长了。

poj1177 求轮廓周长

hdu1255 求面积的交

hdu4419 也可以算求矩形面积的交吧

hdu4052 可以转化模型为求矩形面积的并


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值