题解:
- 按行进行区间合并
- 按列进行区间合并
- 判断行列的重叠部分减去多加的
存储结构:
对于行和列我们要存储三个值,分别为区间左右或上下端点以及一个标识表示那一行或那一列!
- 行或列的标识:当然是行或列相同的哪一个数字
- 左右端点:当然是不相同的一组中较小值和较大值
对于排序:
可以重载小于号,也可以直接在外面写一个cmp
函数传入sort
进行比较!
优先按照行货列的标号从下到大,然后就是按照左端点和右端点!
区间合并:
- 保证在同一行
k == seg.k
- 区间无法合并
ed < seg.l
,则进行上一个区间的保存,同时更新左右端点 - 可以合并,则进行合并,更新右端点
- 区间无法合并
- 不在同一行,直接将上一个区间保存,同时更新新的区间的左右端点以及行或列的标识
k
- 记得最后一个区间的保存,
for
循环无法处理最后一个区间的保存 - 最后将保存的容器还原到原始的
segs
,通过引用传回去!
注意: 对于每次合并当然都得判断起始点是否是-2e9
计数:
每次保存就是一个新区间,将区间长度累加一下即可,cnt += ed - st + 1
去重:
即只要是横着的和竖着的有相交就去减掉一个重合点,判断条件(画个图就知道了):row.k >= col.l && row.k <= col.r && row.r >= col.k && row.l <= col.k
时间复杂度:
- 区间合并:$O(n)$
- 快排:$O(logn)$
- 去重:$O(n^2)$
- 总复杂度为:$O(n^2)$
参考代码
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
typedef long long LL;
struct Node{
int k, l, r;
bool operator < (const Node& w) const {
if(k != w.k) return k < w.k;
else if(l != w.l) return l < w.l;
else return r < w.r;
}
};
int n;
LL cnt;
vector<Node> cols, rows;
void merge(vector<Node>& segs){
sort(segs.begin(), segs.end());
vector<Node> res;
int st = -2e9, ed = st, k = -2e9;
for(auto seg : segs){
if(seg.k == k){
if(ed < seg.l){
if(st != -2e9) res.push_back({k, st, ed}), cnt += ed - st + 1;;
st = seg.l, ed = seg.r;
}else ed = max(ed, seg.r);
}else {
if(st != -2e9) res.push_back({k, st, ed}), cnt += ed - st + 1;;
k = seg.k, st = seg.l, ed = seg.r;
}
}
if(st != -2e9) res.push_back({k, st, ed}), cnt += ed - st + 1;;
segs = res;
}
int main(){
cin >> n;
for(int i = 0; i < n; i++){
int x1, y1, x2, y2;
cin >> x1 >> y1 >> x2 >> y2;
if(x1 == x2) cols.push_back({x1, min(y1, y2), max(y1, y2)});
else rows.push_back({y1, min(x1, x2), max(x1, x2)});
}
merge(cols), merge(rows);
for(auto col : cols)
for(auto row : rows)
if(row.k >= col.l && row.k <= col.r && row.r >= col.k && row.l <= col.k) cnt --;
cout << cnt << endl;
return 0;
}
虽然不影响结果,但x1==x2时应该是要对某一行操作,应该是row.push_back()才对吧?row不是表示“行”的意思么。
x1==x2,说明是两个竖着的,所以col也没问题
矩阵坐标系和数学坐标系的差别,其实都一样
其实重载小于号里面不用对右端点排序的,因为ed = max(ed, seg.r);
bool operator < (const Node& w) const {
if(k != w.k) return k < w.k;
else if(l != w.l) return l < w.l;
else return r < w.r;
}
这里w哪来的呀
真的思路清晰啊,牛批
厉害,思路一样,我代码实现写错了。
好奇为什么排序复杂度是logn
支持一下,虽然是n^2复杂度,但是代码写的可读性比较好~
强啊;
hh,谢谢支持!
是闫总吗?
hh,y总在这里!