0%

2025 United Kingdom and Ireland Programming Contest (UKIEPC 2025) 2025 英国 ICPC——B. Brickwork(判断砖块是否重叠)(扫描线的本质就是遍历一个出一个)(维护一个当前生效的集合)

题目大意

我们试图设计一个墙壁,将其作为2D矩形砖块形状的镶嵌,所有砖块都具有完全的整数坐标和完全的整数大小。

给定这个2D墙壁上砖块的描述,确定墙壁是否确实是一个墙壁——覆盖一个完美的矩形,没有砖块重叠,砖块之间也没有空白空间。这意味着区域内的每个非整数坐标都应该被一个砖块完全覆盖。

image

分别说明样本1、2和3的砖块图示。

输入

  • 一行,包含砖块数量 nn (1n10000001 \le n \le 1\,000\,000)。

  • nn 行,每行描述一个砖块,包括四个整数 x y w hx \ y\ w\ h 分别表示 xy 坐标、宽度、高度 (0x,y1080 \le x, y \le 10^8; 1w,h1081 \le w, h \le 10^8)。

说白了就是这个砖块的位置,还有长宽都告诉你了。呃,但是呢这个砖块的的这个长宽,还有数量比较大。需要你判断一下这些砖块之间有没有重叠

思路讲解

一言以蔽之,我们这道题目所采用的策略就是维护一个在当前激活的 X 区间上不相交的 Y 区间集合。也就是说,我们的这个 activates 集合,它里面存储的是 y 区间。然后 activates 的进出是使用的 event 去控制,去顺序遍历 event 以控制 activates 里面的y 区间集合的进出。

其实扫描线思想的精髓呢,其实就是把二维的问题看成是一维的问题,通过消除偏序关系,维护激活集合。**维护激活的矩形集合。**等方式。

如果说我们维护一个集合,这个集合当中只有当前还生效的矩形,我们是不是会轻松很多?

呃,我们先使用event类来模拟这个矩形的进入和删除。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
struct Event {
ll x,y_st,y_ed,op;
bool operator<(const Event & o) const {
if (x!=o.x) return x<o.x;
return op<o.op;

}
// auto operator<=>(const Event &)const =default;
};
multiset<Event> event_st;
for (int i=0;i<N;++i) {
ll x,y,w,h;
cin>>x>>y>>w>>h;
mnx=min(mnx,x);
mny=min(mny,y);
mxx=max(mxx,x+w);
mxy=max(mxy,y+h);
acc_area+=w*h;
// rect_ls[i]={x,y,w,h};
event_st.insert({x,y,y+h,1});
event_st.insert({x+w,y,y+h,0});
}

然后我们去读取 event 类去模拟这个进入和删除的过程,保持 activates 这个Pair set里面只有这个,已经激活的矩形,那么已经激活的矩形其实就相当于一段线段了(在Y方向上的线段)。我们使用check函数去检查一下,就是我们插入的这个东西,它会不会呃和activs里面本来就有的这个线段重叠(不过,因为activates里面的这个所有的线段都是互不重叠的,所以说判断起来会非常容易,只需要检查前驱和后继即可。)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// 如果假设 activates 是这个互不重叠的,那么肯定没问题
set<pair<ll,ll>> activates;
for (auto &event:event_st) {
auto [x,y_st,y_ed,op]=event;
if (op==1) {
if (!check({y_st,y_ed})) {
cout<<"no\n";
return;
}
activates.insert({y_st,y_ed});
}else {
activates.erase({y_st,y_ed});
}
}
cout<<"yes\n";
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
auto check=[&](pair<ll,ll> y_pair) -> bool {
if (activates.empty()) {
return true;
}
auto it=activates.upper_bound(y_pair);
if (it!=activates.end()) {
if (y_pair.first>=it->second || y_pair.second<=it->first) {

}else {
return false;
}
}
if (it!=activates.begin()) {
it=prev(it);
if (y_pair.first>=it->second || y_pair.second<=it->first) {

}else {
return false;
}
}
return true;
};

AC代码

AC
https://qoj.ac/submission/2011619

AC
https://codeforces.com/gym/106157/submission/361754040

https://qoj.ac/submission/2011657

心路历程(WA,TLE,MLE……)