加载中...

ABC 442 E(极角排序)

E - Laser Takahashi

赛时直接用的 \(atan\) 函数算的极角,卡精度被卡爆了。赛时敲一半才发觉到可以直接用叉乘和一些简单的分讨来比较两个向量的极角大小。可是始终没能找到一个合适的板子。这里贴一个官方题解给的模板,可以直接当作 sort 函数的参数使用,使列表中的所有点按照关于极角的大小升序排序

struct Point{
	int x, y, id;
};
ll det(Point a, Point b){ // 向量 Oa 与 向量 Ob 的叉积
	return 1ll * a.x * b.y - 1ll * b.x * a.y;
}
// 极角排序函数。极角相等时返回0,只有b的极角严格>a时返回1
bool azimuth_cmp(Point a, Point b){ // 供排序函数使用,使得列表中的向量按照极角大小升序排序。极点为(0, 0)
    int ah = (a.y < 0 || (a.y == 0 && a.x < 0));
    int bh = (b.y < 0 || (b.y == 0 && b.x < 0));
    if (ah != bh) return ah < bh; // 这里就是关于点在坐标轴上的一些特判
    return det(a, b) > 0; // a 与 b 的叉积 > 0 当且仅当 b 在 a 的逆时针方向,也就是 b 的极角大小严格大于 a
}

核心原理:利用两个向量叉乘的正负性判断二者之间的顺逆时针方向的相对关系。具体见 计算几何基础

需要特别注意这里对 \(y\) 方向上下半区的处理。这里直接贴官解的设定:

pZ21Dlq.png

对于本题,核心在于将所有点按照极角大小排好序后,需要处理出所有极角相等的点在列表中的最左侧和最右侧位置。这个可以利用上面的 cmp 函数来作进一步判断:对于 \(cmp(p[i], p[i + 1])\),由于已经排好序,因此 \(p[i]\) 的极角一定 \(\leq\) \(p[i + 1]\) 的极角。那么:

  • \(cmp = 0 \rightarrow\) 极角相等
  • \(cmp = 1 \rightarrow\) 极角不相等,\(p[i + 1]\) 极角更大

因此可以 \(O(n)\) 处理出每个位置的 \(l[i], r[i]\)。然后处理每个询问。具体实现见代码。

code

posted @ 2026-01-25 00:50  jxs123  阅读(17)  评论(0)    收藏  举报