Codeforces - 1194E - Count The Rectangles - 扫描线

https://codeforc.es/contest/1194/problem/E

给5000条正常的(同方向不会重叠,也不会退化成点的)线段,他们都是平行坐标轴方向的,求能组成多少个矩形。

先进行坐标偏移,按水平线和垂直线分好类。

用扫描线的思路,从底部的水平线开始往上扫,先标记所有与该条水平线相交的竖直线,加入队列,给竖直线按y排序。

先把结束的竖直线undo掉,然后从这条水平线A的下一条水平线B开始,询问B线覆盖的区间中还有多少标记的竖直线。

注意要么偏移5001,要么把区间查询这里加个特判。防止越界到-1。

慢一点点的代码。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;

const int MAXN = 10001;
int bit[MAXN + 5];

inline int prefix_sum(int x) {
    int res = 0;
    for(; x; x -= x & -x)
        res += bit[x];
    return res;
}

inline void add(int x, int v) {
    for(; x <= MAXN; x += x & -x)
        bit[x] += v;
}

inline int range_sum(int l, int r) {
    return prefix_sum(r) - prefix_sum(l - 1);
}

struct Vertical_Line {
    int x, y1, y2;
    bool operator<(const Vertical_Line& vl) {
        return x != vl.x ? x < vl.x : y1 < vl.y1;
    }
} vl[5005];
int  vtop;

struct Vertical_Line_End {
    int x, y;
    bool operator<(const Vertical_Line_End& vle) {
        return y < vle.y;
    }
} vle[5005];
int vle_back, vle_front;

struct Horizontal_Line {
    int x1, x2, y;
    bool operator<(const Horizontal_Line& hl) {
        return y != hl.y ? y < hl.y : x1 < hl.x1;
    }
} hl[5005];
int htop;

int main() {
#ifdef Yinku
    freopen("Yinku.in", "r", stdin);
    //freopen("Yinku.out", "w", stdout);
#endif // Yinku
    int n;
    while(~scanf("%d", &n)) {
        vtop = 0, htop = 0;
        int x1, y1, x2, y2;
        for(int i = 1; i <= n; i++) {
            scanf("%d%d%d%d", &x1, &y1, &x2, &y2);
            x1 += 5001, y1 += 5001, x2 += 5001, y2 += 5001;
            if(x1 > x2)
                swap(x1, x2);
            if(y1 > y2)
                swap(y1, y2);
            if(x1 == x2) {
                ++vtop;
                vl[vtop].x = x1;
                vl[vtop].y1 = y1;
                vl[vtop].y2 = y2;
            } else {
                ++htop;
                hl[htop].y = y1;
                hl[htop].x1 = x1;
                hl[htop].x2 = x2;
            }
        }
        sort(vl + 1, vl + 1 + vtop);
        sort(hl + 1, hl + 1 + htop);
        ll ans = 0;
        for(int hi = 1; hi <= htop; hi++) {
            vle_front = 1;
            vle_back = 0;
            for(int vi = 1; vi <= vtop; vi++) {
                if(vl[vi].x >= hl[hi].x1 && vl[vi].x <= hl[hi].x2 && vl[vi].y1 <= hl[hi].y && vl[vi].y2 >= hl[hi].y) {
                    add(vl[vi].x, 1);
                    ++vle_back;
                    vle[vle_back].x = vl[vi].x;
                    vle[vle_back].y = vl[vi].y2;
                }
            }
            sort(vle + 1, vle + 1 + vle_back);
            int cury = hl[hi].y;
            for(int hii = hi + 1; hii <= htop; hii++) {
                while(vle_front <= vle_back && vle[vle_front].y < hl[hii].y) {
                    add(vle[vle_front].x, -1);
                    vle_front++;
                }
                int tmp = range_sum(hl[hii].x1, hl[hii].x2);
                ans += (tmp * (tmp - 1) >> 1);
            }
            while(vle_front <= vle_back) {
                add(vle[vle_front].x, -1);
                vle_front++;
            }
        }
        printf("%lld\n", ans);
    }
}

其实一开始把竖直线也按y排序就省掉了后面的排序了的。快了一点点。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;

const int MAXN = 10001;
int bit[MAXN + 5];

inline int prefix_sum(int x) {
    int res = 0;
    for(; x; x -= x & -x)
        res += bit[x];
    return res;
}

inline void add(int x, int v) {
    for(; x <= MAXN; x += x & -x)
        bit[x] += v;
}

inline int range_sum(int l, int r) {
    return prefix_sum(r) - prefix_sum(l - 1);
}

struct Vertical_Line {
    int x, y1, y2;
    bool operator<(const Vertical_Line& vl) {
        return y2 < vl.y2;
    }
} vl[5005];
int  vtop;

struct Vertical_Line_End {
    int x, y;
} vle[5005];
int vle_back, vle_front;

struct Horizontal_Line {
    int x1, x2, y;
    bool operator<(const Horizontal_Line& hl) {
        return y != hl.y ? y < hl.y : x1 < hl.x1;
    }
} hl[5005];
int htop;

int main() {
#ifdef Yinku
    freopen("Yinku.in", "r", stdin);
    //freopen("Yinku.out", "w", stdout);
#endif // Yinku
    int n;
    while(~scanf("%d", &n)) {
        vtop = 0, htop = 0;
        int x1, y1, x2, y2;
        for(int i = 1; i <= n; i++) {
            scanf("%d%d%d%d", &x1, &y1, &x2, &y2);
            x1 += 5001, y1 += 5001, x2 += 5001, y2 += 5001;
            if(x1 > x2)
                swap(x1, x2);
            if(y1 > y2)
                swap(y1, y2);
            if(x1 == x2) {
                ++vtop;
                vl[vtop].x = x1;
                vl[vtop].y1 = y1;
                vl[vtop].y2 = y2;
            } else {
                ++htop;
                hl[htop].y = y1;
                hl[htop].x1 = x1;
                hl[htop].x2 = x2;
            }
        }
        sort(vl + 1, vl + 1 + vtop);
        sort(hl + 1, hl + 1 + htop);
        ll ans = 0;
        for(int hi = 1; hi <= htop; hi++) {
            vle_front = 1;
            vle_back = 0;
            for(int vi = 1; vi <= vtop; vi++) {
                if(vl[vi].x >= hl[hi].x1 && vl[vi].x <= hl[hi].x2 && vl[vi].y1 <= hl[hi].y && vl[vi].y2 >= hl[hi].y) {
                    add(vl[vi].x, 1);
                    ++vle_back;
                    vle[vle_back].x = vl[vi].x;
                    vle[vle_back].y = vl[vi].y2;
                }
            }
            //sort(vle + 1, vle + 1 + vle_back);
            int cury = hl[hi].y;
            for(int hii = hi + 1; hii <= htop; hii++) {
                while(vle_front <= vle_back && vle[vle_front].y < hl[hii].y) {
                    add(vle[vle_front].x, -1);
                    vle_front++;
                }
                int tmp = range_sum(hl[hii].x1, hl[hii].x2);
                ans += (tmp * (tmp - 1) >> 1);
            }
            while(vle_front <= vle_back) {
                add(vle[vle_front].x, -1);
                vle_front++;
            }
        }
        printf("%lld\n", ans);
    }
}

猜你喜欢

转载自www.cnblogs.com/Yinku/p/11195977.html