Segment tree scanning lines

扫描线一般运用在图形上面,它和它的字面意思十分相似,就是一条线在整个图上扫来扫去,它一般被用来解决图形面积,周长等问题。     -------OI Wiki

Find the area and the scan line

P5490 [template] scan lines

in FIG assumed that three rectangular, seeking the union area. Consider each rectangle into two parallel processing to the y-axis segments, line segment marker left +1, -1 line segment marker on the right, with a four-tuple \ ((x, y_1, y_2 , k) \) survive, so we get such a pattern:

in accordance with four-tuple x coordinate ascending sort, we can handle the entire segments by pattern:

different colors of the first treatment period, this pattern can be divided into 5 sections were .
Rectangle consideration each treatment, along the length of the x-axis is easy to know that the current four-tuple x is subtracted on a quad x. We are dealing with a length along the y axis, a maintenance sequence:
1. If the current read a line marked +1, +1 to this section on the sequence, and vice versa --1.
2. Each time the count is greater than the length of the mark to the 0 sequence requirements.
Specific processing:
1. Since the larger the title data, it is necessary discretization, using a mapping array (NUM []) to the original coordinate values.
2. Maintenance segment tree sequence (a sequence corresponding to the i-th item \ ([[i] num, num [i + 1]] \) of this section), each node maintains two values segment tree where: s and CNT, this section represents the value of cnt is labeled, s represents the period cnt> 0 length. When the update, if the current node cnt> 0, then s is the entire length of the segment, i.e. \ (NUM [R & lt +. 1] - NUM [L] \) , otherwise the length of the two child nodes and, because each we only care about the whole query sequence, that segment tree root, so do not need to modify this range marks the next pass.
3. reads a quad \ ((x, y_1, y_2 , k) \)When the first statistic answer, then the sequence \ - ([y_1, y_2 1 ] \) mark this plus k,.

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
using namespace std;
typedef long long lld;
const int N = 100005;
const int M = 1000005;
int n, tot = 0, num[M], maxn = 0;
lld ans = 0;
struct Tree {
    int cnt, s;
} e[M << 2];
struct node {
    int x, l, r, k;
} p[N << 1];
void update(int i, int l, int r) {
    if(e[i].cnt > 0) e[i].s = num[r + 1] - num[l];// l, r表示num[l]到num[r + 1]这一段
    else e[i].s = e[i << 1].s + e[i << 1 | 1].s;
}
void add(int i, int l, int r, int nl, int nr, int k) {
    if(l >= nl && r <= nr) {
        e[i].cnt += k; update(i, l, r);
        return ;
    }
    int mid = (l + r) >> 1;
    if(nl <= mid) add(i << 1, l, mid, nl, nr, k);
    if(nr > mid) add(i << 1 | 1, mid + 1, r, nl, nr, k);
    update(i, l, r);
}
int get() {
    return e[1].s;
}
void add1(int x1, int x2, int y1, int y2) {
    p[++tot].x = x1; p[tot].l = y1; p[tot].r = y2; p[tot].k = 1;
    p[++tot].x = x2; p[tot].l = y1; p[tot].r = y2; p[tot].k = -1;
    maxn = max(y1, max(y2, maxn));
}
int a[N], b[N], c[N], d[N];
vector <int> tmp;
bool cmp(node a, node b) {
    return a.x < b.x;
}
int main() {
//  freopen("data.in", "r", stdin);
    scanf("%d", &n);
    for(int i = 1, x1, x2, y1, y2; i <= n; i++) {
        scanf("%d%d%d%d", &x1, &y1, &x2, &y2);
        a[i] = x1, b[i] = x2, c[i] = y1, d[i] = y2;
        tmp.push_back(y1); tmp.push_back(y2);
    }
    sort(tmp.begin(), tmp.end());//离散化
    for(int i = 1; i <= n; i++) {
        int save1 = c[i], save2 = d[i];
        c[i] = lower_bound(tmp.begin(), tmp.end(), c[i]) - tmp.begin() + 1;
        d[i] = lower_bound(tmp.begin(), tmp.end(), d[i]) - tmp.begin() + 1;
        num[c[i]] = save1, num[d[i]] = save2;//映射原值
        add1(a[i], b[i], c[i], d[i]);//添加四元组
    }
    sort(p + 1, p + 1 + tot, cmp);//按照x排序
    add(1, 1, maxn, p[1].l, p[1].r - 1, p[1].k);//添加第一条线段
    for(int i = 2; i <= tot; i++) {
        ans = ans + (1ll * get() * (p[i].x - p[i - 1].x));//统计答案,长乘宽
        add(1, 1, maxn, p[i].l, p[i].r - 1, p[i].k);//修改序列
    }
    printf("%lld", ans);
    return 0;
}

Seeking a rectangular perimeter scan line

P1856 [USACO5.5] Picture rectangular perimeter

The method is similar to find the area, discrete processing, modify and query interval tree line as above.
Statistics Answer: When reading a quad, to record the current value of the query, make modifications, then query once, the answer to the increased amount of the absolute value of the difference between the two queries. Proof Obviously, not much here bb.
Details:
1. Such statistics can only perimeter parallel to the y-axis and a line segment, we need to each point x, y coordinates and then repeat the switching operation.
2. If the same sort quad x-coordinate, the top surface k = 1 (first plus and minus have no effect on the answer to statistics, if the first minus plus answer may lead to too large)

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
using namespace std;
const int N = 5005;
const int M = 20015;
const int F = 10001;
int a[N], b[N], c[N], d[N], n, tot = 0;
int num[M << 2];
long long ans = 0;
struct node {
    int x, l, r, k;
} p[N << 1];
void add(int x1, int y1, int x2, int y2) {
    if(y1 > y2) swap(y1, y2);
    p[++tot].x = x1, p[tot].l = y1, p[tot].r = y2, p[tot].k = 1;
    p[++tot].x = x2, p[tot].l = y1, p[tot].r = y2, p[tot].k = -1;
}
struct tree {
    int s, cnt;
} e[M << 2];
vector <int> tmp, opt;
void update(int i, int l, int r) {
    if(e[i].cnt > 0) e[i].s = num[r + 1] - num[l];
    else e[i].s = e[i << 1].s + e[i << 1 | 1].s;
}
void add(int i, int l, int r, int nl, int nr, int k) {
    if(l >= nl && r <= nr) {
        e[i].cnt += k; update(i, l, r);
        return ;
    }
    int mid = (l + r) >> 1;
    if(nl <= mid) add(i << 1, l, mid, nl, nr, k);
    if(nr > mid) add(i << 1 | 1, mid + 1, r, nl, nr, k);
    update(i, l, r);
}
int get() {
    return e[1].s;
}
bool cmp(node a, node b) {
    if(a.x == b.x) return a.k > b.k; //k = 1排在前面
    return a.x < b.x;
}
void solve() {
    sort(p + 1, p + 1 + tot, cmp);
    for(int i = 1; i <= tot; i++) {
        long long per = get();
        add(1, 1, tot, p[i].l, p[i].r - 1, p[i].k);
        ans = (ans + abs(per - get()));
    }
}
int main() {
//  freopen("data.in", "r", stdin);
    scanf("%d", &n);
    for(int i = 1, x1, x2, y1, y2; i <= n; i++) {
        scanf("%d%d%d%d", &x1, &y1, &x2, &y2);
        a[i] = x1, b[i] = y1, c[i] = x2, d[i] = y2;
        tmp.push_back(y1); tmp.push_back(y2);
        opt.push_back(x1), opt.push_back(x2);
    }
    sort(tmp.begin(), tmp.end());
    for(int i = 1; i <= n; i++) {
        int save1 = b[i], save2 = d[i];
        b[i] = lower_bound(tmp.begin(), tmp.end(), b[i]) - tmp.begin() + 1;
        d[i] = lower_bound(tmp.begin(), tmp.end(), d[i]) - tmp.begin() + 1;
        num[b[i]] = save1, num[d[i]] = save2;
        add(a[i], b[i], c[i], d[i]);
    }
    solve();
    for(int i = 0; i < (M << 2); i++) e[i].s = e[i].cnt = 0;
    memset(num, 0, sizeof(num));
    tot = 0;
    sort(opt.begin(), opt.end());
    for(int i = 1; i <= n; i++) {
        int save1 = a[i], save2 = c[i];
        a[i] = lower_bound(opt.begin(), opt.end(), a[i]) - opt.begin() + 1;
        c[i] = lower_bound(opt.begin(), opt.end(), c[i]) - opt.begin() + 1;
        num[a[i]] = save1, num[c[i]] = save2;
        add(b[i], a[i], d[i], c[i]);
    }
    solve();
    printf("%lld", ans);
    return 0;
}

Guess you like

Origin www.cnblogs.com/mcggvc/p/12538960.html