세그먼트 트리 주사선

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

지역 및 스캔 라인을 찾기

P5490 [템플릿] 주사선

도 상정하는 세 개의 직사각형 결합 영역을 찾는. Y 축 세그먼트에 두 개의 병렬 처리로 각각 사각형을 고려 선분 마커는 +1 왼쪽 -1 오른쪽 선분 마커, 네 튜플과 \ ((X, y_1, y_2 , K) \) 우리는 이러한 패턴을 얻을 수 있도록, 생존

네 튜플 X는 오름차순 정렬 좌표 따른를 우리가 패턴에 의해 전체 세그먼트를 처리 할 수있다 :

첫 번째 치료 기간의 다른 색이 패턴은 5 개의 섹션으로 분할 될 수 있었다 .
사각형 고려 x 축의 길이를 따라 각각의 치료가 알고 쉽다는 현재 네 개의 튜플 X는 차감 쿼드 X에서. 우리는 Y 축, 유지 보수 순서를 따라 길이 다루고있다 :
1. 현재이 라인이 --1 역이 순서 섹션, 그리고 그에게 +1, +1을 표시 읽으면.
2.마다 카운트가 0 시퀀스 요구 마크의 길이보다 크다.
특정 처리 :
1. 큰 타이틀 데이터 때문에, 좌표 값을 원래로 매핑 어레이 (NUM [])를 이용하여 필요한 이산화이다.
2. 정비 세그먼트 트리 시퀀스 (시퀀스의 i 번째 항목에 대응 \ ([I] NUM, NUM [I + 1] \) 이 섹션의) 각 노드는 두 값 세그먼트 트리 유지 : S 및 CNT를 이 섹션에서는, CNT의 값은 표지 나타내는 기간 CNT> 0 s의 길이를 나타낸다. 업데이트가 현재 노드 CNT> 0, 다음에 s 경우, 세그먼트의 전체 길이 인 경우, 즉 \ (NUM [R & LT + 1이다.] - NUM [L] \) , 그렇지 않으면 두 개의 자식 노드의 길이와, 각 때문에 우리는 지금이 범위 마크에게 다음 패스를 수정할 필요가 없습니다, 전체 질의 시퀀스, 그 세그먼트 트리 루트에 관심.
3. 쿼드 판독 \ ((X, y_1, y_2 , k)를 \)제 통계 응답은 다음 순서 때 \ - ([y_1, y_2 1 ] \) 이 플러스 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;
}

주사선 경계 직사각형을 찾는

P1856 [USACO5.5에 화상 직사각형 주변

상기 방법은 공간, 개별 처리를 수정하고 상기와 같은 쿼리 간격 트리 라인을 찾는 유사하다.
통계 답변 : 질의의 현재 값을 기록, 쿼드을 읽을 때, 수정을, 다음 쿼리 한 번, 두 쿼리의 차이의 절대 값의 증가 된 양에 대한 대답. 증명은 물론,별로 여기 BB.
상세 :
1. 그러한 통계 만 둘레, Y 축과 선분에 평행 한 수, 우리는 각 점의 X, Y 좌표로해야하고 스위칭 동작을 반복한다.
2. 동일한 종류 쿼드 x 좌표 경우 상부 표면 K = 1 (제 1 더하기 및 빼기 제 플러스 마이너스 대답이 너무 크면 발생할 수있는 경우, 통계에 대한 응답에 영향을 미치지 않음)

#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;
}

추천

출처www.cnblogs.com/mcggvc/p/12538960.html