[The 17th Zhejiang Provincial Collegiate Programming Contest]-H. Huge Clouds (2020年浙江省赛,几何,思维)
[The 17th Zhejiang Provincial Collegiate Programming Contest]-H. Huge Clouds (2020年浙江省赛,几何,思维)
题面:
题意:
有\(\mathit n\)个光源和\(\mathit m\)个挡板,在X轴上的点到某个光源的线段中如果不经过任何挡板,则表明该点可以被那个光源的找到。如果某个点不会被任何一个光源找到,那么该点是黑暗的。现在问你X轴上黑暗部分的长度。
思路:
我们枚举每一个光源和每一个线段,通过基础的几何算法可以求出无法被该点光源照亮的区间。
那么共有\(N*M\)个区间,我们需要快速的求出每一个光源对应的区间的交集。
我们不妨将区间拆为两个事件,每一个事件保存3个信息,分别为:是该区间的左or右端点,x轴上的位置,光源编号,我们即可对所有事件\(\{pos,tpye,i\}\)按照位置升序排序后如下处理:
(1) 当 \(\mathit t\) 从 \(l − ϵ\) 增大至 \(\mathit l\) 时,接下来的位置里,点光源\(i\)被遮挡次数增加 1。
(2) 当 t 从 \(\mathit r\) 增大至 \(r + ϵ\) 时,接下来的位置里,点光源 \(\mathit i\) 被遮挡次数减少 1。
用桶数组维护每个点光源被遮挡的次数以及被至少遮挡一次的点光源数量\(num\)。
若 \(num = n\),则该事件到上一个事件中间的部分未被照亮。
时间复杂度 \(O(n*m*log(nm))\)。
代码:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef double db;
const db eps = 1e-6;
int sgn(db x)
{
if (fabs(x) < eps) {
return 0;
}
return x > 0 ? 1 : -1;
}
struct Point {
db x, y;
Point() {}
Point(db _x, db _y)
{
x = _x; y = _y;
}
Point operator - (const Point &b) const
{
return Point(x - b.x, y - b.y);
}
db operator * (const Point &b) const
{
return x * b.x + y * b.y;
}
db operator ^ (const Point &b) const
{
return x * b.y - y * b.x;
}
bool operator < (const Point &b) const
{
return (sgn(x - b.x) == 0 ? sgn(y - b.y) < 0 : x < b.x);
}
};
Point getpoint(const Point &a, const Point &b, const Point &c, const Point &d)
{
Point res;
db a1, b1, c1, a2, b2, c2;
a1 = a.y - b.y, b1 = b.x - a.x, c1 = a.x * b.y - b.x * a.y;
a2 = c.y - d.y, b2 = d.x - c.x, c2 = c.x * d.y - d.x * c.y;
res.x = (b1 * c2 - b2 * c1) / (a1 * b2 - a2 * b1);
res.y = -(a1 * c2 - a2 * c1) / (a1 * b2 - a2 * b1);
return res;
}
struct Line {
Point s, e;
Line() {}
Line(Point _s, Point _e)
{
s = _s; e = _e;
}
pair<int, Point> operator &(const Line &b)const
{
Point res = s;
if (sgn((s - e) ^ (b.s - b.e)) == 0) {
if (sgn((s - b.e) ^ (b.s - b.e)) == 0) {
return make_pair(0, res); //重合
} else { return make_pair(1, res); } //平行
}
res = getpoint(s, e, b.s, b.e);
return make_pair(2, res);
}
bool point_on_line(Point p)
{
return sgn((p - s) ^ (e - s)) == 0;
}
bool point_on_seg(Point p)
{
return sgn((p - s) ^ (e - s)) == 0 && sgn((p - s) * (p - e)) <= 0;
}
void adjust()
{
if (sgn(s.y - e.y) > 0) {
swap(s, e);
}
}
};
int n, m;
Point a[505];
Line b[505];
int cnt[505];
vector<pair<double, double> > c[505];
#define mp make_pair
struct node {
double pos;
int tpye;
int id;
node() {}
node(double _pos, int _type, int _id)
{
pos = _pos;
tpye = _type;
id = _id;
}
bool operator < (const node &b) const
{
return sgn(pos - b.pos) < 0;
}
};
std::vector<node> v;
int main()
{
int t;
scanf("%d", &t);
pair<int, Point> res;
Line xz = Line(Point(-1, 0), Point(1, 0));
while (t--) {
scanf("%d %d", &n, &m);
for (int i = 1; i <= n; ++i) {
scanf("%lf %lf", &a[i].x, &a[i].y);
}
for (int i = 1; i <= m; ++i) {
scanf("%lf %lf %lf %lf", &b[i].s.x, &b[i].s.y, &b[i].e.x, &b[i].e.y);
b[i].adjust();
}
for (int i = 1; i <= n; ++i) {
for (int j = 1; j <= m; ++j) {
if (b[j].point_on_line(a[i])) {
if (b[j].point_on_seg(a[i])) {
c[i].push_back(mp(-1e18, 1e18));
}
continue;
}
if (sgn(b[j].s.y - a[i].y) >= 0) {
continue;
}
if (sgn(a[i].y - b[j].e.y) > 0) {
double l, r;
res = Line(a[i], b[j].s) & xz;
l = res.second.x;
res = Line(a[i], b[j].e) & xz;
r = res.second.x;
if (sgn(l - r) > 0) {
swap(l, r);
}
c[i].push_back(mp(l, r));
} else {
double cp;
res = Line(a[i], b[j].s) & xz;
cp = res.second.x;
if (sgn((a[i] - b[j].s) ^ (b[j].e-b[j].s)) >= 0) {
c[i].push_back(mp(-1e18, cp));
} else {
c[i].push_back(mp(cp, 1e18));
}
}
}
}
for (int i = 1; i <= n; ++i) {
for (auto &x : c[i]) {
v.push_back(node(x.first, 0, i));
v.push_back(node(x.second, 1, i));
}
}
sort(v.begin(), v.end());
int num = 0;
double ans = 0;
double pre;
for (auto &now : v) {
if (num == n) {
ans += now.pos - pre;
}
if (now.tpye == 0) {
if (cnt[now.id]++ == 0) {
num++;
}
} else {
if (--cnt[now.id] == 0) {
num--;
}
}
pre = now.pos;
}
if (sgn(ans - 1e9) > 0) {
printf("-1\n");
} else {
printf("%.6f\n", ans);
}
for (int i = 1; i <= n; ++i) {
c[i].clear();
cnt[i] = 0;
}
v.clear();
}
return 0;
}
本博客为本人原创,如需转载,请必须声明博客的源地址。
本人博客地址为:www.cnblogs.com/qieqiemin/
希望所写的文章对您有帮助。