https://codeforc.es/contest/1194/problem/Ec++
給5000條正常的(同方向不會重疊,也不會退化成點的)線段,他們都是平行座標軸方向的,求能組成多少個矩形。spa
先進行座標偏移,按水平線和垂直線分好類。code
用掃描線的思路,從底部的水平線開始往上掃,先標記全部與該條水平線相交的豎直線,加入隊列,給豎直線按y排序。排序
先把結束的豎直線undo掉,而後從這條水平線A的下一條水平線B開始,詢問B線覆蓋的區間中還有多少標記的豎直線。隊列
注意要麼偏移5001,要麼把區間查詢這裏加個特判。防止越界到-1。get
慢一點點的代碼。it
#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排序就省掉了後面的排序了的。快了一點點。class
#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); } }