关于整体二分
  • 板块CF1386C Joker
  • 楼主abruce
  • 当前回复6
  • 已保存回复6
  • 发布时间2021/4/17 22:25
  • 上次更新2023/11/5 00:24:28
查看原帖
关于整体二分
104324
abruce楼主2021/4/17 22:25

下面是本题在网上的一篇题解。

原题链接 这是一道有(du)趣(liu)的数据结构题

首先发现无修改询问,所以珂以莫队。然后发现你要维护当前的图是否为二分图,这显然珂以大力LCT维护最大生成树。然后复杂度就变成了惊人的O(NNlogN)O(N\sqrt N\log N),附加大常数惊喜。显然,不加任何卡常技巧,这是过不去的;用了许多卡常技巧,这也是过不去的。

我们必须考虑换个路子。观察一下Subtask33,珂以发现当询问中的ll为常数时,有一个临界值rr,使得:k[l,r)\forall k\in [l,r),询问(l,k)(l,k)对应的图不是二分图;k[r,m]\forall k\in [r,m],询问(l,k)(l,k)对应的图是二分图。所以这个Subtask便珂以预处理出这个临界值,这显然珂以用LCT在O(NlogN)O(N\log N)内实现。

我们把上述对于ll的临界值定义为AlA_l。进一步思考,我们会发现:l1l2\forall l_1\le l_2,不等式Al1Al2A_{l_1}\le A_{l_2}恒成立,即数组AA是单调不减的。又由于LCT支持加边和删边,于是,我们珂以双指针来预处理出数组AA。这样复杂度依旧是优秀的O(NlogN)O(N\log N),珂以通过所有Subtask。

Q: 窝不会LCT肿么办?

A: 那就用那个不用LCT的做法呗。

不用LCT是什么做法?我们珂以发现,LCT在上述算法中,只是来维护最大生成树,判断二分图的。那为什么上述算法中LCT是必要的呢?因为在双指针的过程中,我们要在加边和删边的操作之余判断二分图,当加边和删边无任何顺序时,LCT是必要的。

那么不用LCT的做法,就是要让加边和删边的操作有顺序,即每一次加边时把这个边放入一个栈里,删边时就弹栈。这时删边操作就变成了回滚操作。于是我们珂以用常数较小的可撤销并查集来代替常数巨大的LCT。

然而,双指针并不能用一个栈来维护。于是我们珂以考虑分治:定义分治函数SS维护四个值l,r,L,Rl,r,L,R,其中前提条件满足i[l,r],Ai[L,R]\forall i\in[l,r],A_i\in[L,R],且在调用S(l,r,L,R)S(l,r,L,R)时,可撤销并查集内已有[1,l1][r+1,m][1,l-1]\cup [r+1,m]内的所有边。设M=(l+r)/2M=(l+r)/2,则珂以先在O(n)O(n)内算出AMA_M。这时i[l,M1],AiAM\forall i\in[l,M-1],A_i\le A_M,且i[M+1,r],AiAM\forall i\in [M+1,r],A_i\ge A_M。所以珂以在S(l,r,L,R)S(l,r,L,R)中调用S(l,M1,L,AM)S(l,M-1,L,A_M)S(M+1,r,AM,R)S(M+1,r,A_M,R)。注意要在调用之前往可撤销并查集内插入相应的边,然后在调用结束后回滚掉。又因为SS调用中区间的总长度为O(N)O(N)级别,再加上可撤销并查集的O(logN)O(\log N),所以时间复杂度为O(Nlog2N)O(N\log^2 N)。因为常数较小,所以跑得和LCT的O(NlogN)O(N\log N)差不多快。

代码?不存在的。

我有几个疑惑。
1.为什么调用S(l,r,L,R)S(l,r,L,R)时,可撤销并查集内要有[1,l1][r+1,m][1,l-1]\cup [r+1,m]内的所有边?
2.怎么在O(n)O(n)内算出AMA_M,加哪些边?

2021/4/17 22:25
加载中...