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

注意!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系我们删除。



 
粤ICP备14056181号  © 2014-2020 ITdaan.com