线段树扫描线模板(求面积和周长) Picture

求面积:

#include <iostream>
#include <stdio.h>
#include <algorithm>
using namespace std;
const int N = 205;

struct Line
{
    int st;         //记录上下边
    double s, e, x; //记录x的左右边
    bool operator<(const Line &a) const
    {
        return x < a.x;
    }
} line[N];

struct node
{
    int cnt; //表示次数
    double len;
} tree[N * 4];

void buildtree(int node, int start, int end)
{
    tree[node].len = tree[node].cnt = 0;
    if (start == end)
        return;
    int mid = (start + end) / 2;
    buildtree(node * 2, start, mid);
    buildtree(node * 2 + 1, mid + 1, end);
}
double lisan[N];
void pushup(int node, int start, int end)
{
    if (tree[node].cnt) //如果有值的话 cnt>0
    {
        tree[node].len = lisan[end + 1] - lisan[start];
    }
    else if (start == end)
    {
        tree[node].len = 0; //更新操作
    }
    else
        tree[node].len = tree[node << 1].len + tree[node << 1 | 1].len;
}
void update(int node, int start, int end, int L, int R, int val)
{
    if (L > end || R < start)
        return;
    else if (start == end)
    {
        tree[node].cnt += val;
        pushup(node, start, end);
        return;
    }
    else if (start >= L && end <= R)
    {
        tree[node].cnt += val;
        pushup(node, start, end);
        return;
    }
    int mid = (start + end) >> 1;
    // if (L <= mid)
    update(node * 2, start, mid, L, R, val);
    // if (R > mid)
    update(node * 2 + 1, mid + 1, end, L, R, val);
    pushup(node, start, end);
}

bool cmp(double a, double b)
{
    return a < b;
}
int main()
{
    int n, t = 1;
    while (~scanf("%d", &n) && n)
    {
        int i, j = 1;
        for (i = 1; i <= n; i++)
        {
            double x1, x2, yy1, y2;
            scanf("%lf%lf%lf%lf", &x1, &yy1, &x2, &y2);
            line[j].s = yy1, line[j].e = y2, line[j].x = x1, line[j].st = 1, lisan[j++] = yy1;
            line[j].s = yy1, line[j].e = y2, line[j].x = x2, line[j].st = -1, lisan[j++] = y2;
        }
        sort(line + 1, line + 1 + n * 2);
        sort(lisan + 1, lisan + 1 + n * 2, cmp);
        int cnt = unique(lisan + 1, lisan + 1 + n * 2) - (lisan + 1) - 1;
        buildtree(1, 1, cnt);
        double ans = 0;
        for (i = 1; i <= n * 2; i++) //从一开始是因为把line[1]的s和e更新
        {
            ans += tree[1].len * (line[i].x - line[i - 1].x);
            int yl = lower_bound(lisan + 1, lisan + 1 + cnt, line[i].s) - lisan;
            int yr = lower_bound(lisan + 1, lisan + 1 + cnt, line[i].e) - lisan - 1;
            update(1, 1, cnt, yl, yr, line[i].st);
        }
        printf("Test case #%d\nTotal explored area: %.2lf\n\n", t++, ans);
    }
    return 0;
}

求周长(只扫描一遍,时间竟然多了)

#include <iostream>
#include <stdio.h>
#include <algorithm>
using namespace std;
const int N = 500005;

struct Line
{
    int st; //记录上下边
    int h;      //高度h  
    double s, e, y; //记录x的左右边
    bool operator<(const Line &a) const
    {
        return y < a.y;
    }
} line[N];
struct node
{
    int l, r;
    bool lc, rc;
    int cnt; //表示次数
    double len;
    int num;
} tree[N * 4];

void buildtree(int node, int start, int end)
{
    tree[node].l = start, tree[node].r = end;
    tree[node].len = tree[node].cnt = tree[node].num = tree[node].lc = tree[node].rc = 0;
    if (start == end)
        return;
    int mid = (start + end) / 2;
    buildtree(node * 2, start, mid);
    buildtree(node * 2 + 1, mid + 1, end);
}
double lisan[N];
void pushup(int node, int start, int end)
{
    if (tree[node].cnt) //如果有值的话 cnt>0
    {
        tree[node].len = lisan[end + 1] - lisan[start];
        tree[node].lc = tree[node].rc = 1;
        tree[node].num = 1;
        return;
    }
    if (start == end)
    {
        tree[node].lc = tree[node].rc = tree[node].num = 0;
        tree[node].len = 0; //更新操作
    }
    else
    {
        tree[node].len = tree[node << 1].len + tree[node << 1 | 1].len;
        tree[node].lc = tree[node << 1].lc;
        tree[node].rc = tree[node << 1 | 1].rc;
        tree[node].num = tree[node << 1].num + tree[node << 1 | 1].num - (tree[node << 1].rc & tree[node << 1 | 1].lc); // 如果都被覆盖则就是一个了。
    }
}
void update(int node, int start, int end, int L, int R, int val)
{
    if (L > end || R < start)
        return;
    else if (start == end)
    {
        tree[node].cnt += val;
        pushup(node, start, end);
        return;
    }
    else if (start >= L && end <= R)
    {
        tree[node].cnt += val;
        pushup(node, start, end);
        return;
    }
    int mid = (start + end) >> 1;
    // if (L <= mid)
    update(node * 2, start, mid, L, R, val);
    // if (R > mid)
    update(node * 2 + 1, mid + 1, end, L, R, val);
    pushup(node, start, end);
}

bool cmp(double a, double b)
{
    return a < b;
}
int main()
{
    int n;
    scanf("%d", &n);
    int i, j = 1, jj = 1;
    for (i = 1; i <= n; i++)
    {
        double x1, x2, yy1, y2;
        scanf("%lf%lf%lf%lf", &x1, &yy1, &x2, &y2);
        line[j].s = x1, line[j].e = x2, line[j].y = line[j].h = yy1, line[j].st = 1, lisan[j++] = x1;
        line[j].s = x1, line[j].e = x2, line[j].y = line[j].h = y2, line[j].st = -1, lisan[j++] = x2;
    }
    sort(line + 1, line + 1 + n * 2);
    sort(lisan + 1, lisan + 1 + n * 2, cmp);
    int cnt = unique(lisan + 1, lisan + 1 + n * 2) - (lisan + 1) - 1;
    buildtree(1, 1, cnt);
    long long ans = 0;
    for (i = 1; i <= n * 2; i++) //从一开始是因为把line[1]的s和e更新
    {
        int last = tree[1].len;
        int xl = lower_bound(lisan + 1, lisan + 1 + cnt, line[i].s) - lisan;
        int xr = lower_bound(lisan + 1, lisan + 1 + cnt, line[i].e) - lisan - 1;
        update(1, 1, cnt, xl, xr, line[i].st);
        ans += abs(last - tree[1].len); // 横线的
        ans += (line[i + 1].h - line[i].h) * 2 * tree[1].num;
    }
    printf("%lld\n", ans);
    return 0;
}

求周长(扫描两边的)(时间竟然比上面短, 但内存占用大)

#include <iostream>
#include <stdio.h>
#include <algorithm>
using namespace std;
const int N = 500005;

struct Line
{
    int st;         //记录上下边
    double s, e, y; //记录x的左右边
    bool operator<(const Line &a) const
    {
        return y < a.y;
    }
} line[N];

struct Line2
{
    int st;         //记录上下边
    double s, e, x; //记录x的左右边
    bool operator<(const Line2 &a) const
    {
        return x < a.x;
    }
} line2[N];

struct node
{
    int cnt; //表示次数
    double len;
} tree[N * 4];

void buildtree(int node, int start, int end)
{
    tree[node].len = tree[node].cnt = 0;
    if (start == end)
        return;
    int mid = (start + end) / 2;
    buildtree(node * 2, start, mid);
    buildtree(node * 2 + 1, mid + 1, end);
}
double lisan[N], lisan2[N];
void pushup(int node, int start, int end)
{
    if (tree[node].cnt) //如果有值的话 cnt>0
    {
        tree[node].len = lisan[end + 1] - lisan[start];
        return;
    }
    if (start == end)
    {
        tree[node].len = 0; //更新操作
    }
    else
        tree[node].len = tree[node << 1].len + tree[node << 1 | 1].len;
}
void update(int node, int start, int end, int L, int R, int val)
{
    if (L > end || R < start)
        return;
    else if (start == end)
    {
        tree[node].cnt += val;
        pushup(node, start, end);
        return;
    }
    else if (start >= L && end <= R)
    {
        tree[node].cnt += val;
        pushup(node, start, end);
        return;
    }
    int mid = (start + end) >> 1;
    // if (L <= mid)
    update(node * 2, start, mid, L, R, val);
    // if (R > mid)
    update(node * 2 + 1, mid + 1, end, L, R, val);
    pushup(node, start, end);
}

bool cmp(double a, double b)
{
    return a < b;
}
int main()
{
    int n;
    scanf("%d", &n);
    int i, j = 1, jj = 1;
    for (i = 1; i <= n; i++)
    {
        double x1, x2, yy1, y2;
        scanf("%lf%lf%lf%lf", &x1, &yy1, &x2, &y2);
        line[j].s = x1, line[j].e = x2, line[j].y = yy1, line[j].st = 1, lisan[j++] = x1;
        line[j].s = x1, line[j].e = x2, line[j].y = y2, line[j].st = -1, lisan[j++] = x2;

        line2[jj].s = yy1, line2[jj].e = y2, line2[jj].x = x1, line2[jj].st = 1, lisan2[jj++] = yy1;
        line2[jj].s = yy1, line2[jj].e = y2, line2[jj].x = x2, line2[jj].st = -1, lisan2[jj++] = y2;
    }
    sort(line + 1, line + 1 + n * 2);
    sort(lisan + 1, lisan + 1 + n * 2, cmp);
    int cnt = unique(lisan + 1, lisan + 1 + n * 2) - (lisan + 1) - 1;
    buildtree(1, 1, cnt);
    long long ans = 0;
    for (i = 1; i <= n * 2; i++) //从一开始是因为把line[1]的s和e更新
    {
        int last = tree[1].len;
        int xl = lower_bound(lisan + 1, lisan + 1 + cnt, line[i].s) - lisan;
        int xr = lower_bound(lisan + 1, lisan + 1 + cnt, line[i].e) - lisan - 1;
        update(1, 1, cnt, xl, xr, line[i].st);
        ans += abs(last - tree[1].len);
    }
    // printf("%lld\n", ans);

    sort(line2 + 1, line2 + 1 + n * 2);
    sort(lisan2 + 1, lisan2 + 1 + n * 2, cmp);
    for (i = 1; i <= n * 2; i++)
    {
        lisan[i] = lisan2[i];
    }
    cnt = unique(lisan + 1, lisan + 1 + n * 2) - (lisan + 1) - 1;
    buildtree(1, 1, cnt);
    for (i = 1; i <= n * 2; i++) //从一开始是因为把line2[1]的s和e更新
    {
        int last = tree[1].len;
        int xl = lower_bound(lisan + 1, lisan + 1 + cnt, line2[i].s) - lisan;
        int xr = lower_bound(lisan + 1, lisan + 1 + cnt, line2[i].e) - lisan - 1;
        update(1, 1, cnt, xl, xr, line2[i].st);
        ans += abs(last - tree[1].len);
    }
    printf("%lld\n", ans);
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值