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
", 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
", ans);
}
}