• HDU 1828 Picture


    HDU_1828

        以前只用离散化的思想写过这个题,现在又结合上线段树重新写了一遍。如果希望只沿一个方向扫描一遍就求出周长的话,那么相当于需要用两种方式分别求水平和竖直部分的周长。比如我们沿x方向扫描,那么竖直方向上的边长就需要通过矩形覆盖扫描线的总长度的变化值来计算,而水平方向上的边长就需要用点数乘以区间跨度去计算。

        其实感觉也可以在两个方法中任选一个,分别沿x、y方向各扫描一遍,也可以求出最后的周长。

        此外,如果我们沿x方向扫描,并按矩形覆盖的扫描线的总长度的变化值去计算竖直部分的边长的话,那么最初在对线段排序时,同一x值的线段一定要是矩形右边的边在前,是矩形左边的边在后。也就是说同一x位置上,要先进行添加边的操作,再进行删除边的操作,这是因为如果两条竖直边重合或有公共部分的话,我们如果先删再添就会多计算一部分长度。

    #include<stdio.h>
    #include<string.h>
    #include<stdlib.h>
    #define MAXD 10010
    int N, M, ty[4 * MAXD], num[4 * MAXD], lc[4 * MAXD], rc[4 * MAXD], len[4 * MAXD], cnt[4 * MAXD];
    struct Seg
    {
    int x, y1, y2, col;
    }seg[4 * MAXD];
    int cmps(const void *_p, const void *_q)
    {
    Seg *p = (Seg *)_p, *q = (Seg *)_q;
    if(p->x == q->x)
    return p->col > q->col ? -1 : 1;
    return p->x < q->x ? -1 : 1;
    }
    int cmpy(const void *_p, const void *_q)
    {
    int *p = (int *)_p, *q = (int *)_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;
    len[cur] = lc[cur] = rc[cur] = num[cur] = cnt[cur] = 0;
    if(x == y)
    return ;
    build(ls, x, mid);
    build(rs, mid + 1, y);
    }
    void update(int cur, int x, int y)
    {
    int ls = cur << 1, rs = (cur << 1) | 1;
    if(cnt[cur])
    {
    len[cur] = ty[y + 1] - ty[x];
    lc[cur] = rc[cur] = 1;
    num[cur] = 2;
    }
    else if(x == y)
    len[cur] = lc[cur] = rc[cur] = num[cur] = 0;
    else
    {
    len[cur] = len[ls] + len[rs];
    lc[cur] = lc[ls], rc[cur] = rc[rs];
    num[cur] = num[ls] + num[rs];
    if(rc[ls] && lc[rs])
    num[cur] -= 2;
    }
    }
    void init()
    {
    int i, j, k, x1, y1, x2, y2;
    for(i = 0; i < N; i ++)
    {
    scanf("%d%d%d%d", &x1, &y1, &x2, &y2);
    j = i << 1, k = (i << 1) | 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;
    }
    N <<= 1;
    qsort(seg, N, sizeof(seg[0]), cmps);
    qsort(ty, N, sizeof(ty[0]), cmpy);
    M = -1;
    for(i = 0; i < N; i ++)
    if(i == 0 || ty[i] != ty[i - 1])
    ty[++ M] = ty[i];
    build(1, 0, M - 1);
    }
    void refresh(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)
    refresh(ls, x, mid, s, t, c);
    if(mid + 1 <= t)
    refresh(rs, mid + 1, y, s, t, c);
    update(cur, x, y);
    }
    int BS(int y)
    {
    int mid, min = 0, max = M + 1;
    for(;;)
    {
    mid = (min + max) >> 1;
    if(mid == min)
    break;
    if(ty[mid] <= y)
    min = mid;
    else
    max = mid;
    }
    return mid;
    }
    void solve()
    {
    int i, j, k, ans, prelen;
    ans = prelen = 0;
    seg[N].x = seg[N - 1].x;
    for(i = 0; i < N; i ++)
    {
    j = BS(seg[i].y1), k = BS(seg[i].y2);
    refresh(1, 0, M - 1, j, k - 1, seg[i].col);
    ans += num[1] * (seg[i + 1].x - seg[i].x);
    ans += abs(len[1] - prelen);
    prelen = len[1];
    }
    printf("%d\n", ans);
    }
    int main()
    {
    while(scanf("%d", &N) == 1)
    {
    init();
    solve();
    }
    return 0;
    }

     

  • 相关阅读:
    Django模型层Meta内部类详解
    jquery checkbox的相关操作——全选、反选、获得所有选中的checkbox
    c# 委托与异步调用
    DataTable转成List集合
    c# winform 自动升级
    C# winform单元格的formatted值的类型错误 DataGridView中CheckBox列运行时候System.FormatException异常
    C#创建无窗体的应用程序
    sql 一个表的字段更新至另一个字段的方法
    datagridview 获取选中行的索引
    CHECKEDLISTBOX用法总结
  • 原文地址:https://www.cnblogs.com/staginner/p/2438320.html
Copyright © 2020-2023  润新知