CF1641C - Anonymity Is Important
非常抽象,建议自己把数据放代码上跑,理解过程。
并查集的另类用法。
我们设 \(fa_i\) 去维护包含 \(i\) 的全健康区间。具体来说,对于一个区间 \([l,r]\),我们将 \(fa_{l\sim r}\) 全部都接在 \(fa_{r+1}\) 上。这样会有两个用处:
- 如果 \(fa_i\ne i\) 那么 \(i\) 是健康的。
- \(fa_i\) 代表包含 \(i\) 的全健康区间的最右边端点 +1。
我们再设置一个数组 \(L_i\) 代表 \(i\) 左边 至少一病区间 的左端点在哪里。如果有多个取离 \(i\) 最近的。
那么对于询问一个点 \(x\),我们就看:
- 如果 \(fa_x\ne x\) 那么 \(i\) 没有生病。
- 设 \(t=fa_{x+1}\),代表右端点大于 \(x\) ,且包含 \(x+1\),的健康区间。设 \(p=L_t\) 代表,包含那个健康区间的 至少一病区间 的最左边端点。如果这个 至少一病区间 内只有 \(x\) 了(也就是 \(fa_p=x\))那么他就生病了。否则就是 N/A。
怎么修改?
如果是加入一个健康区间,那么就是不断地将 \(l\sim r\) 变成 \(r+1\) 的子孙。(实际操作中,如果枚举到 \(i\) 的时候,发现 \(i\) 已经是 \(r+1\) 的子孙,那么就可以直接结束了,保证时间复杂度。)
如果是加入一个至少一病区间,那么就更新一下 \(L_i\) 即可。