Escaneo de líneas para área y perímetro (plantilla, árbol de segmentos de línea)

Introduccion

Calcule rápidamente el área o el perímetro de múltiples áreas de cobertura rectangular.

Lograr

Encontrar área

La línea de exploración de oi_wiki se explica muy claramente, es decir, la longitud del borde inferior cubierto por cada exploración se multiplica por la suma de la altura.
Principalmente preste atención a los detalles de la implementación del código. Aquí hay un registro del proceso de discretización del árbol de segmentos de línea.
HDU1542-Atlantis

#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>

using namespace std;
#define endl '\n'
typedef long long ll;

const int N = 3000;

struct snode {
    double x, y1, y2;
    int flag;
    
};

bool cmp(const snode &a, const snode &b) {
    return a.x < b.x;
}

struct tnode {
    double sum, l, r;
};

tnode st[N << 2];
snode seg[N];
double num[N];
int lazy[N << 2];

void pushup(int rt) {
    if(lazy[rt] > 0) {
        st[rt].sum = st[rt].r - st[rt].l;
    } else {
        st[rt].sum = st[rt << 1].sum + st[rt << 1 | 1].sum;
    }
}

void update(double L, double R, int rt, int flag) {
    if(L == st[rt].l && R == st[rt].r) {
        lazy[rt] += flag;
        pushup(rt);
        return ;
    }
    if(st[rt << 1].r > L) //>而不是>=?不能等于,否则区间长度为0,会进入死循环。
        update(L, min(R, st[rt << 1].r), rt << 1, flag);
    if(st[rt << 1 | 1].l < R) 
        update(max(L, st[rt << 1 | 1].l), R, rt << 1 | 1, flag);
    pushup(rt);
}

void build(int lef, int rig, int rt) {
    if(rig - lef > 1) { //由于mid公用,所以>1就可以
        int mid = (lef + rig) / 2;
        st[rt].l = num[lef]; //离散化
        st[rt].r = num[rig];
        build(lef, mid, rt << 1);
        build(mid, rig, rt << 1 | 1); //mid而不是mid+1?因为是线段,头尾需要相连,否则答案会少值
        pushup(rt);
    } else {
        st[rt].l = num[lef];
        st[rt].r = num[rig];
        st[rt].sum = 0;
    }
}


int main() {
     //freopen("1.txt", "r", stdin);
     //freopen("test.txt", "w", stdout);
    
    ios::sync_with_stdio(false);
    int n;
    int cases = 0;
    while(1) {
        scanf("%d", &n);
        if(!n) break;
        cases++;
        for(int i = 0; i < n; i++) {
            double x1, x2, y1, y2;
            scanf("%lf %lf %lf %lf", &x1, &y1, &x2, &y2);
            seg[i].x = x1; seg[i].y1 = y1; seg[i].y2 = y2; 
            seg[i].flag = 1;
            seg[i + n].x = x2; seg[i + n].y1 = y1; seg[i + n].y2 = y2; 
            seg[i + n].flag = -1;

            num[i + 1] = y1;
            num[i + 1 + n] = y2;
        }
        sort(num + 1, num + 1 + (2 * n)); //离散化
        sort(seg, seg + 2 * n, cmp);
        memset(lazy, 0, sizeof lazy);
        build(1, 2 * n, 1);
        double ans = 0;
        update(seg[0].y1, seg[0].y2, 1, seg[0].flag);
        for(int i = 1; i < 2 * n; i++) {
            ans += (seg[i].x - seg[i - 1].x) * st[1].sum;
            update(seg[i].y1, seg[i].y2, 1, seg[i].flag);
        }
        printf("Test case #%d\n", cases);
        printf("Total explored area: %.2lf\n\n", ans);
    }
}

Mendigar perímetro

El perímetro se puede escanear primero en la dirección del eje xy luego en la dirección del eje y.
El método específico es encontrar la suma del valor absoluto de la longitud total del segmento de línea antes de restar la longitud total del segmento de línea después de cubrir el segmento de línea es la respuesta.
Después de leer los blogs de los hermanos mayores, también hay una manera de obtener la circunferencia total mediante un escaneo, y hay tiempo para compensar.
POJ1177-Picture

#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>

using namespace std;
#define endl '\n'
typedef long long ll;

const int N = 5001;

struct snode {
    int x, y1, y2;
    int flag;
    
};

bool cmp(const snode &a, const snode &b) {
    return a.x < b.x;
}

struct tnode {
    int sum, l, r;
};

int ran[N << 1][4];
tnode st[N << 3];
snode seg[N << 1];
int num[N << 1];
int lazy[N << 3];

void pushup(int rt) {
    if(lazy[rt] > 0) {
        st[rt].sum = st[rt].r - st[rt].l;
    } else {
        st[rt].sum = st[rt << 1].sum + st[rt << 1 | 1].sum;
    }
}

void update(int L, int R, int rt, int flag) {
    if(L == st[rt].l && R == st[rt].r) {
        lazy[rt] += flag;
        pushup(rt);
        return ;
    }
    if(st[rt << 1].r > L) //>而不是>=?不能等于,否则长度为0,会进入死循环。
        update(L, min(R, st[rt << 1].r), rt << 1, flag);
    if(st[rt << 1 | 1].l < R) 
        update(max(L, st[rt << 1 | 1].l), R, rt << 1 | 1, flag);
    pushup(rt);
}

void build(int lef, int rig, int rt) {
    if(rig - lef > 1) { //由于mid公用,所以>1就可以
        int mid = (lef + rig) / 2;
        st[rt].l = num[lef];
        st[rt].r = num[rig];
        build(lef, mid, rt << 1);
        build(mid, rig, rt << 1 | 1); //mid而不是mid+1?因为是线段,头尾需要相连,否则会少值
        pushup(rt);
    } else {
        st[rt].l = num[lef];
        st[rt].r = num[rig];
        st[rt].sum = 0;
    }
}


int main() {
     //freopen("1.txt", "r", stdin);
     //freopen("test.txt", "w", stdout);
    int n;
    scanf("%d", &n);
    for(int i = 0; i < n; i++) {
        scanf("%d %d %d %d", &ran[i][0], &ran[i][1], &ran[i][2], &ran[i][3]);
    }
    for(int i = 0; i < n; i++) {
        int x1 = ran[i][0], y1 = ran[i][1], x2 = ran[i][2], y2 = ran[i][3];
        seg[i].x = x1; seg[i].y1 = y1; seg[i].y2 = y2; 
        seg[i].flag = 1;
        seg[i + n].x = x2; seg[i + n].y1 = y1; seg[i + n].y2 = y2; 
        seg[i + n].flag = -1;
        num[i + 1] = y1;
        num[i + 1 + n] = y2;
    }
    sort(num + 1, num + 1 + (2 * n));
    sort(seg, seg + 2 * n, cmp);
    memset(lazy, 0, sizeof lazy);
    build(1, 2 * n, 1);
    int ans1 = 0;
    //update(seg[0].y1, seg[0].y2, 1, seg[0].flag);
    for(int i = 0; i < 2 * n; i++) {
        int t = st[1].sum;
        update(seg[i].y1, seg[i].y2, 1, seg[i].flag);
        ans1 += abs(st[1].sum - t);
        
    }

    for(int i = 0; i < n; i++) {
        int x1 = ran[i][0], y1 = ran[i][1], x2 = ran[i][2], y2 = ran[i][3];
        seg[i].x = y1; seg[i].y1 = x1; seg[i].y2 = x2; 
        seg[i].flag = 1;
        seg[i + n].x = y2; seg[i + n].y1 = x1; seg[i + n].y2 = x2; 
        seg[i + n].flag = -1;
        num[i + 1] = x1;
        num[i + 1 + n] = x2;
    }
    sort(num + 1, num + 1 + (2 * n));
    sort(seg, seg + 2 * n, cmp);
    memset(lazy, 0, sizeof lazy);
    build(1, 2 * n, 1);
    //update(seg[0].y1, seg[0].y2, 1, seg[0].flag);
    int ans2 = 0;
    for(int i = 0; i < 2 * n; i++) {
        int t = st[1].sum;
        update(seg[i].y1, seg[i].y2, 1, seg[i].flag);
        ans2 += abs(st[1].sum - t);
    }
    cout << ans1 + ans2 << endl;
}

Supongo que te gusta

Origin www.cnblogs.com/limil/p/12701921.html
Recomendado
Clasificación