2020-2021 ACM-ICPC Brazil Subregional Programming Contest M. Machine Gun
在二维平面上给出 $n$ 个敌军的坐标 $A_i(x_i, y_i)$, 再进行q次强制在线询问:
每次询问将给出一个炮台坐标 $(x_m, y_m)$, 需找出所有能被坐标 $(x_m, y_m)$ 攻击到的敌军的下标. 这里定义炮台 $(x_m, y_m)$ 能攻击到的范围是 $y = y_m \pm \frac{x - x_m}{2}$ 所夹出来的右半部分, 包括边界.
接下来将这些下标按照升序排序, 记为$i_0, i_1, \dots i_k$
计算结果 $(\sum_{j=0}^{k-1} i_j \cdot 5782344^j) \mod 10^9 + 7$, 输出结果.
$1 \le x_i, y_i \le 10^9, 1 \le n, q, \le 10^5$
保证所有查询中被攻击到的敌军总数不超过 $10^6$, 保证$x_i > 0, x_m < 0$
有两种考虑方式.
第一种
施鹏飞学长讲的:
注意到每个炮台所能攻击到的范围角度是固定的, 所以为了更好地刻画炮台 攻击的覆盖范围, 我们可以将炮台的攻击范围投影到$x=0$这条线上; 类似地, 将每个敌军以同样的角度都投影到$x=0$这条线上. 如果两条线段有交集, 那么 该炮台就可以攻击到这个敌军.
问题就等价地转化为: 在数轴上给出 $n$ 个区间, 再进行 $q$ 次 查询, 每次查询给出一个区间, 询问 $n$ 个区间中有哪些区间与询问的区间相交.
形式化一下, 我们要找这样的区间: $l_i \le r_m, r_i \ge l_m$, 其中 $[l_m, r_m]$是询问区间.
第二种
将坐标进行伸缩变换:
- 把两条边的夹角改成直角: $y \to 2y$
- 把 $x$ 轴 $y$ 轴顺时针转 $\frac{\pi}{4}$: $(x, y) \to (x - y, x + y)$
总的来说, 把 $(x, y) \to (x - 2y, x + 2y)$.
也就是说, 令每个点的坐标为 $\begin{cases} x’ = x - 2y \\ y’ = x + 2y \end{cases}$
也就是得到下面这种东西:
然后找这样的点: $x_i’ \ge x_m’, y_i’ \ge y_m'$
实际上两者没有本质区别, 最后得到的关系都是一样的, 只是思考方式的不同.
当然还有第三种方法, 就是直接推算满足什么样的条件的点会被炮塔打到. 得到的结果是一样的.
到这里就转换成了二维偏序问题. 先对一维排序, 然后再放到数据结构上排第二维.
这里需要的不是个数, 而是所有的点的下标. 所以考虑用线段树, 每个节点开一个 vector
按第二维的顺序存 第二维和原下标(需要第二维排序, 需要原下标).
二分确定第一维的范围, 在线段树上区间查询第二维即可. 二维偏序就是这个套路.
复杂度 $O(n \log n + q \log^2 n)$
|
|