线段树+扫描线问题

线段树+扫描线问题。


Atlantis

线段树+扫描线第一题。

之前看过一次,只不过没实现。

看了胡浩的线段树专辑再去敲得,其实基本和他写的一样。

只是update那里稍有不同,这里划分区间应该是l~midmid~r,而不是l~midmid+1~r,因为这里指的是连续的区间,而不是离散的点。

题目传送:HDU - 1542 - Atlantis

AC代码:

#include <map>
#include <set>
#include <list>
#include <cmath>
#include <deque>
#include <queue>
#include <stack>
#include <bitset>
#include <cctype>
#include <cstdio>
#include <string>
#include <vector>
#include <complex>
#include <cstdlib>
#include <cstring>
#include <fstream>
#include <sstream>
#include <utility>
#include <iostream>
#include <algorithm>
#include <functional>
#define LL long long
#define INF 0x7fffffff
using namespace std;

const int maxn = 20005;

struct Seg {
    double l, r, h;
    int c;
    Seg() {}
    Seg(double _l, double _r, double _h, double _c) : l(_l), r(_r), h(_h), c(_c) {}
    bool operator < (const Seg& a) const {
        return h < a.h;
    }
}S[maxn << 2];
double X[maxn << 2];

int cover[maxn << 2];//统计区间的下边比上边多几条边
double sum[maxn << 2]; //用于统计长度

int b_search(double key, int n, double X[]) {
    int l = 0, r = n - 1;
    while(l <= r) {
        int mid = (l + r) >> 1;
        if(X[mid] == key) return mid;
        if(X[mid] < key) l = mid + 1;
        else r = mid - 1;
    }
    return -1;
}

void pushup(int rt, int l, int r) {
    if(cover[rt]) sum[rt] = X[r] - X[l];
    else if(l == r) sum[rt] = 0;
    else sum[rt] = sum[rt << 1] + sum[rt << 1 | 1];
}

void update(int rt, int l, int r, int L, int R, int c) {
    if(L <= l && r <= R) {
        cover[rt] += c;
        pushup(rt, l, r);
        return;
    }
    int mid = (l + r) >> 1;
    if(mid > L) update(rt << 1, l, mid, L, R, c);
    if(mid < R) update(rt << 1 | 1, mid, r, L, R, c);
    pushup(rt, l, r);
}

int main() {
    int n, cas = 1;
    while(scanf("%d", &n) != EOF) {
        if(n == 0) break;
        double a, b, c, d;
        int m = 0;
        for(int i = 0; i < n; i ++) {
            scanf("%lf %lf %lf %lf", &a, &b, &c, &d);
            X[m] = a;
            S[m ++] = Seg(a, c, b, 1);
            X[m] = c;
            S[m ++] = Seg(a, c, d, -1);
        }
        sort(S, S + m);
        sort(X, X + m);
        int k = 1;
        for(int i = 1; i < m; i ++) {
            if(X[i] != X[i - 1]) X[k ++] = X[i];
        }
        memset(cover, 0, sizeof(cover));
        memset(sum, 0, sizeof(sum));
        double ans = 0;
        for(int i = 0; i < m - 1; i ++) {
            int l = b_search(S[i].l, k, X);
            int r = b_search(S[i].r, k, X);
            update(1, 0, k - 1, l, r, S[i].c);
            ans += sum[1] * (S[i + 1].h - S[i].h);
        }
        printf("Test case #%d\nTotal explored area: %.2lf\n\n", cas ++, ans);
    }
    return 0;
}

你可能感兴趣的:(线段树,扫描线)