天神下凡
https://zybuluo.com/ysner/note/1176892 题面 给出 \(n\) 个圆心同在 \(x\) 轴上的圆,问圆的轮廓将平面分为几块?( 保证圆互不相交 ) \(n\leq3*10^5\) \(r\leq10^9,x\leq10^9\) 解析 经过观察,可以发现,如果一个圆的直径被其它小圆的直径完全覆盖,就会产生额外一贡献。 因为圆在一条直线上,我们只用关心其在直线上的一部分,即可以 用直径代替一个圆 。 一条直线再次被覆盖?能想到什么? 线段树?栈? \(method\ 1\) 并查集 据说这是我的原创方法? 在手玩样例时,我发现, 每次产生贡献的前一步都是把已联通(通过圆相切的方式)的两个点作为一个圆直径的两端点 。 如何判断两点是否联通? 每覆盖一条直线,两端点就连通了,此时两端点中间的点就没用了,直接把两端点纳入同一并查集即可。 当然,两端点联通有一种方式叫 在同一圆直径的两端 ,即存在同圆,这会影响答案,要排序除掉。 由于半径范围(即直径两端点范围)过大,要用 \(map\) 。 于是复杂度达到了 \(O(nlog^2n)\) ,但时间比为 \(1.16s/3s\) ,不虚。(并查集+ \(map\) ) 可以通过离散化达到 \(O(nlogn)\) #include<iostream> #include<cmath> #include