zoukankan      html  css  js  c++  java
  • HDU 1542 Atlantis

    HDU_1542

        如果我们将矩形左右两条边拓展成直线的话,这样平面就被分成了若干个区域,而每个区域内矩形覆盖的面积就等于这个区域的宽度乘以该区域内y轴方向上矩形覆盖的线段的长度和。

        于是我们可以把y坐标离散化并建立线段树,然后沿x轴的方向进行扫描,每当遇到一条矩形左边的竖直边,就将其并到线段树中,每当遇到一条矩形右边的竖直边,就将线段树中以前并上的对应的左边的竖直边从线段树中删除。同时,每次在操作之前都可以将当前新扫描到的面积累加起来。

    为了能够表述“并”与“删除”,我们可以在线段树中用一个数组cnt表示这个节点表示的区间被覆盖了多少次,而不能简单的当成染色问题来对待,因为如果一个区间被覆盖了多次,删除的时候只能删除掉一次的覆盖记录,而不能全部删去。

    更多和扫描线相关的可以参考胡浩的博客:http://www.notonlysuccess.com/index.php/segment-tree-complete/

    #include<stdio.h>
    #include<string.h>
    #include<stdlib.h>
    #include<math.h>
    #define MAXD 210
    #define zero 1e-8
    int N, M, Y, cnt[4 * MAXD];
    double ty[MAXD], dy[4 * MAXD];
    struct Seg
    {
    double x, y1, y2;
    int col;
    }seg[4 * MAXD];
    int dcmp(double x)
    {
    return fabs(x) < zero ? 0 : (x < 0 ? -1 : 1);
    }
    int cmps(const void *_p, const void *_q)
    {
    Seg *p = (Seg *)_p, *q = (Seg *)_q;
    return p->x < q->x ? -1 : 1;
    }
    int cmpy(const void *_p, const void *_q)
    {
    double *p = (double *)_p, *q = (double *)_q;
    return *p < *q ? -1 : 1;
    }
    void build(int cur, int x, int y)
    {
    int mid = (x + y) >> 1, ls = cur << 1, rs = (cur << 1) | 1;
    dy[cur] = cnt[cur] = 0;
    if(x == y)
    return ;
    build(ls, x, mid);
    build(rs, mid + 1, y);
    }
    void init()
    {
    int i, j, k;
    double x1, y1, x2, y2;
    M = N << 1;
    for(i = 1; i <= N; i ++)
    {
    scanf("%lf%lf%lf%lf", &x1, &y1, &x2, &y2);
    j = (i << 1) - 1, k = i << 1;
    seg[j].x = x1, seg[k].x = x2;
    seg[j].y1 = seg[k].y1 = y1, seg[j].y2 = seg[k].y2 = y2;
    seg[j].col = 1, seg[k].col = -1;
    ty[j] = y1, ty[k] = y2;
    }
    qsort(seg + 1, M, sizeof(seg[0]), cmps);
    qsort(ty + 1, M, sizeof(ty[0]), cmpy);
    build(1, 1, M - 1);
    }
    void update(int cur, int x, int y)
    {
    int ls = cur << 1, rs = (cur << 1) | 1;
    if(cnt[cur])
    dy[cur] = ty[y + 1] - ty[x];
    else
    {
    if(x == y)
    dy[cur] = 0;
    else
    dy[cur] = dy[ls] + dy[rs];
    }
    }
    void color(int cur, int x, int y, int s, int t, int c)
    {
    int mid = (x + y) >> 1, ls = cur << 1, rs = (cur << 1) | 1;
    if(x >= s && y <= t)
    {
    cnt[cur] += c;
    update(cur, x, y);
    return ;
    }
    if(mid >= s)
    color(ls, x, mid, s, t, c);
    if(mid + 1 <= t)
    color(rs, mid + 1, y, s, t, c);
    update(cur, x, y);
    }
    int BS(double y)
    {
    int mid, min = 1, max = M + 1;
    for(;;)
    {
    mid = (min + max) / 2;
    if(mid == min)
    break;
    if(dcmp(ty[mid] - y) <= 0)
    min = mid;
    else
    max = mid;
    }
    return mid;
    }
    void solve()
    {
    int i, j, k;
    double ans = 0;
    for(i = 1; i < M; i ++)
    {
    j = BS(seg[i].y1), k = BS(seg[i].y2);
    if(j < k)
    color(1, 1, M - 1, j, k - 1, seg[i].col);
    ans += dy[1] * (seg[i + 1].x - seg[i].x);
    }
    printf("Total explored area: %.2f\n", ans);
    }
    int main()
    {
    int t = 0;
    for(;;)
    {
    scanf("%d", &N);
    if(!N)
    break;
    init();
    printf("Test case #%d\n", ++ t);
    solve();
    printf("\n");
    }
    return 0;
    }

     

  • 相关阅读:
    QTreeWidget创建
    Qt QTreeWidget节点的添加+双击响应+删除详解(转)
    Qt QTreeWidget 树形结构实现(转)
    QMessageBox类学习:
    QAction类详解:
    Qt事件和信号的区别 .
    Qt消息机制和事件(二)
    Qt消息机制和事件(一)
    初步开始学习图
    图中最短路径算法(Dijkstra算法)(转)
  • 原文地址:https://www.cnblogs.com/staginner/p/2437102.html
Copyright © 2011-2022 走看看