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