点此看题面

大致题意: 给你一张图以及每条边的出现时间和消失时间,让你求每个时间段这张图是否是二分图。

二分图性质

二分图有一个比较简单的性质,即二分图中不存在奇环

于是题目就变成了:让你求每个时间段这张图是否不存在奇环。

\(LCT\)动态维护图连通性

关于\(LCT\),详见这篇博客:LCT入门

接下来我们开始讨论如何用\(LCT\)动态维护图连通性。

\(LCT\)动态维护树连通性,应该是比较简单,因为\(LCT\)本身就是一棵树,加边删边都很容易。

而维护图连通性最麻烦的一点,就是在于会出现环,而这样\(LCT\)就无法按照一般的方式来加边删边了。

那么,有没有什么办法,使得既能维护图连通性,又不会使\(LCT\)上出现环呢?

这时就有一个比较贪心的想法。

考虑到每条边最后都是要删掉的,那么当构成环时,我们就可以将该环中最早要被删掉的边给删去,因为这样一来不会影响连通性,二来又可以化环为链,十分巧妙。

但这个方法唯一美中不足的地方就在于,它是一个离线算法,遇上强制在线就无能为力。

不过,这题可以离线做,就没有问题了。

具体实现过程中,我们可以把边看作节点,记录下被删的时间(真正的点被删除时间可设为\(INF\))。

每个节点记录下该子树内被删时间最早的节点编号,出现环时将会构成环的那条链抠出,然后更新即可。

维护是否不存在奇环

接下来我们要考虑如何维护奇环个数。

我们可以记录下每个节点子树内有多少条边,当出现环时,判断是否为奇环,若是则将计数器加\(1\)。同理,当删除环时,判断是否为奇环,若是则将计数器减\(1\)。输出答案时判断计数器是否为\(0\)即可。

代码

  1. #include<bits/stdc++.h>
  2. #define Type template<typename I>
  3. #define N 100000
  4. #define M 200000
  5. #define swap(x,y) (x^=y^=x^=y)
  6. #define INF 1e9
  7. using namespace std;
  8. int n,m,t,flag,tag[N+M+5];
  9. struct Operate
  10. {
  11. int x,y,pos,Begin,End;
  12. }o1[M+5],o2[M+5];
  13. class Class_FIO
  14. {
  15. private:
  16. #define Fsize 100000
  17. #define tc() (A==B&&(B=(A=Fin)+fread(Fin,1,Fsize,stdin),A==B)?EOF:*A++)
  18. char ch,*A,*B,Fin[Fsize];
  19. public:
  20. Class_FIO() {A=B=Fin;}
  21. Type inline void read(I& x) {x=0;while(!isdigit(ch=tc()));while(x=(x<<3)+(x<<1)+(ch&15),isdigit(ch=tc()));}
  22. template<typename I,typename... A> inline void read(I& x,A&... y) {read(x),read(y...);}
  23. }F;
  24. class Class_LCT//LCT动态维护图连通性
  25. {
  26. private:
  27. #define SIZE (N+M)
  28. #define PushUp(x)\//上传子节点信息
  29. (\
  30. node[x].Size=node[node[x].Son[0]].Size+node[node[x].Son[1]].Size+(x>n),node[x].Min=x,\
  31. Val[node[x].Min]>Val[node[node[x].Son[0]].Min]&&(node[x].Min=node[node[x].Son[0]].Min),\
  32. Val[node[x].Min]>Val[node[node[x].Son[1]].Min]&&(node[x].Min=node[node[x].Son[1]].Min)\
  33. )
  34. #define Rever(x) (swap(node[x].Son[0],node[x].Son[1]),node[x].Rev^=1)
  35. #define PushDown(x) (node[x].Rev&&(Rever(node[x].Son[0]),Rever(node[x].Son[1]),node[x].Rev=0))
  36. #define Which(x) (node[node[x].Father].Son[1]==x)
  37. #define Connect(x,y,d) (node[node[x].Father=y].Son[d]=x)
  38. #define IsRoot(x) (node[node[x].Father].Son[0]^x&&node[node[x].Father].Son[1]^x)
  39. #define MakeRoot(x) (Access(x),Splay(x),Rever(x))
  40. #define Split(x,y) (MakeRoot(x),Access(y),Splay(y))
  41. int Stack[SIZE+5];
  42. struct Tree
  43. {
  44. int Min,Size,Rev,Father,Son[2];
  45. }node[SIZE+5];
  46. inline void Rotate(int x)
  47. {
  48. register int fa=node[x].Father,pa=node[fa].Father,d=Which(x);
  49. !IsRoot(fa)&&(node[pa].Son[Which(fa)]=x),node[x].Father=pa,Connect(node[x].Son[d^1],fa,d),Connect(fa,x,d^1),PushUp(fa),PushUp(x);
  50. }
  51. inline void Splay(int x)
  52. {
  53. register int fa=x,Top=0;
  54. while(Stack[++Top]=fa,!IsRoot(fa)) fa=node[fa].Father;
  55. while(Top) PushDown(Stack[Top]),--Top;
  56. while(!IsRoot(x)) fa=node[x].Father,!IsRoot(fa)&&(Rotate(Which(x)^Which(fa)?x:fa),0),Rotate(x);
  57. }
  58. inline void Access(int x) {for(register int son=0;x;x=node[son=x].Father) Splay(x),node[x].Son[1]=son,PushUp(x);}
  59. public:
  60. int Val[SIZE+5];
  61. Class_LCT() {Val[0]=INF;}
  62. inline void Init(int len) {for(register int i=1;i<=len;++i) Val[i]=INF,node[i].Min=i;}//将真正的点被删除时间设为INF
  63. inline void Link(int x,int y) {MakeRoot(x),FindRoot(y)^x&&(node[x].Father=y);}
  64. inline void Cut(int x,int y) {MakeRoot(x),!(FindRoot(y)^x)&&!(node[y].Father^x)&&!node[y].Son[0]&&(node[y].Father=node[x].Son[1]=0,PushUp(x));}
  65. inline int FindRoot(int x)
  66. {
  67. Access(x),Splay(x);
  68. while(node[x].Son[0]) PushDown(x),x=node[x].Son[0];
  69. return Splay(x),x;
  70. }
  71. inline int QueryMin(int x,int y) {return Split(x,y),node[y].Min;}//查询子树内最早被删除的边的编号
  72. inline int QuerySize(int x,int y) {return Split(x,y),node[y].Size;}//查询子树内有多少条边
  73. #undef SIZE
  74. }LCT;
  75. inline bool cmp1(Operate x,Operate y) {return x.Begin<y.Begin;}//将边按出现时间排序
  76. inline bool cmp2(Operate x,Operate y) {return x.End<y.End;}//将边按消失时间排序
  77. inline void Add(int pos)//加入一条边
  78. {
  79. register int x=o1[pos].x,y=o1[pos].y,z=o1[pos].pos;
  80. if(!(x^y)) return (void)(tag[z]=1,++flag);//如果是自环,标记该边为形成奇环的边,并将计数器加1
  81. if(LCT.Val[z]=o1[pos].End,LCT.FindRoot(x)^LCT.FindRoot(y)) return LCT.Link(x,z),LCT.Link(z,y);//如果不构成环,直接连边
  82. register int p=LCT.QueryMin(x,y);//查询将形成环的这条链中最早被删掉的边的编号
  83. if(LCT.Val[z]<LCT.Val[p]) return (void)(!(LCT.QuerySize(x,y)&1)&&(tag[z]=1,++flag));//如果当前插入的这条边先被删去,判断是否为奇环,然后退出函数
  84. !(LCT.QuerySize(x,y)&1)&&(tag[p]=1,++flag),LCT.Cut(o1[p-n].x,p),LCT.Cut(p,o1[p-n].y),LCT.Link(x,z),LCT.Link(z,y);//否则,先判断是否为奇环,再删掉这条链中最早被删掉的边,然后插入当前边
  85. }
  86. inline void Del(int pos)//删除一条边
  87. {
  88. register int x=o2[pos].x,y=o2[pos].y,z=o2[pos].pos;
  89. if(tag[z]) return (void)(--flag);//如果这条边在一个奇环上,则将奇环个数减1
  90. !(LCT.FindRoot(x)^LCT.FindRoot(z))&&!(LCT.FindRoot(y)^LCT.FindRoot(z))&&(LCT.Cut(x,z),LCT.Cut(z,y),0);//如果这条边还在图中,则将其删除
  91. }
  92. int main()
  93. {
  94. register int i,p1=1,p2=1;
  95. for(F.read(n,m,t),LCT.Init(n+m),i=1;i<=m;++i) F.read(o1[i].x,o1[i].y,o1[i].Begin,o1[i].End);//读入
  96. for(sort(o1+1,o1+m+1,cmp1),i=1;i<=m;++i) o1[i].pos=n+i,o2[i]=o1[i];
  97. for(sort(o2+1,o2+m+1,cmp2),i=1;i<=t;++i)
  98. {
  99. while(p1<=m&&o1[p1].Begin<i) Add(p1++);while(p2<=m&&o2[p2].End<i) Del(p2++);//加入和删除边
  100. puts(flag?"No":"Yes");//判断是否有奇环,输出答案
  101. }
  102. return 0;
  103. }

【BZOJ4025】二分图(LCT动态维护图连通性)的更多相关文章

  1. ☆ [NOI2014] 魔法森林 「LCT动态维护最小生成树」

    题目类型:\(LCT\)动态维护最小生成树 传送门:>Here< 题意:带权无向图,每条边有权值\(a[i],b[i]\).要求一条从\(1\)到\(N\)的路径,使得这条路径上的\(Ma ...

  2. ☆ [WC2006] 水管局长 「LCT动态维护最小生成树」

    题目类型:\(LCT\)动态维护最小生成树 传送门:>Here< 题意:给出一张简单无向图,要求找到两点间的一条路径,使其最长边最小.同时有删边操作 解题思路 两点间路径的最长边最小,也就 ...

  3. BZOJ2959长跑——LCT+并查集(LCT动态维护边双连通分量)

    题目描述 某校开展了同学们喜闻乐见的阳光长跑活动.为了能“为祖国健康工作五十年”,同学们纷纷离开寝室,离开教室,离开实验室,到操场参加3000米长跑运动.一时间操场上熙熙攘攘,摩肩接踵,盛况空前. 为 ...

  4. BZOJ 3510 - 首都 「 $LCT$ 动态维护树的重心」

    这题 FlashHu 的优化思路值得借鉴 前置引理 树中所有点到某个点的距离和中,到重心的距离和是最小的. 把两棵树通过某一点相连得到一颗新的树,新的树的重心必然在连接原来两棵树重心的路径上. 一棵树 ...

  5. [BZOJ4025] 二分图 LCT/(线段树分治+并查集)

    4025: 二分图 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 2667  Solved: 989[Submit][Status][Discuss] ...

  6. BZOJ4998星球联盟——LCT+并查集(LCT动态维护边双连通分量)

    题目描述 在遥远的S星系中一共有N个星球,编号为1…N.其中的一些星球决定组成联盟,以方便相互间的交流.但是,组成 联盟的首要条件就是交通条件.初始时,在这N个星球间有M条太空隧道.每条太空隧道连接两 ...

  7. bzoj4025: 二分图 lct

    题意:带增删边的查询二分图 题解:因为二分图肯定带奇环,lct维护,每次要加入一条边之前判断会不会构成环,如果会就把最先会删除的边删掉,然后如果是奇环就打个标记,然后把奇环数++,删除的时候,把标记删 ...

  8. 洛谷P4234 最小差值生成树(lct动态维护最小生成树)

    题目描述 给定一个标号为从 11 到 nn 的.有 mm 条边的无向图,求边权最大值与最小值的差值最小的生成树. 输入输出格式 输入格式:   第一行两个数 n, mn,m ,表示图的点和边的数量. ...

  9. bzoj4025 二分图 LCT + 最小生成树

    题目传送门 https://lydsy.com/JudgeOnline/problem.php?id=4025 题解 貌似这道题有一个非常简单的做法是线段树分治+并查集. 可是我是为了练 LCT 来做 ...

随机推荐

  1. 1.Ioc&DI和Spring

    1.面向对象回顾和案例 面向对象程序设计:1 2 3 4 案例分析: 需求分析: 报表功能:     报表服务类,检索数据,并生成图标     报表生成器类,生成不同格式的报表文件,例如PDF格式.H ...

  2. spring boot mysql 事务

    mysql默认 事务自动提交.即:每条insert/update/delete语句,不需要程序手工提交事务,而是mysql自行提交了. 如果我们想实现程序事务提交,需要事先关闭mysql的自动提交事务 ...

  3. python -- Microsoft Visual C++ 14.0 is required. Get it with "Microsoft Visual C++ Build Tools": http://landinghub.visualstudio.com/visual-cpp-build-tools

    用python读取hive数据,引用下面包. #!/usr/bin/env python import pyhs2 as hive 先按照它 pip install pyhs2 出现错误 Collec ...

  4. python安装包的时候报错

    python安装包的时候报错 今天兴致勃勃的安装了一个paramiko包,过程很顺利,但是到结尾的时候报错,这就让人不爽了. 所以呢,需要安装一个名为python-dev的软件包. 该软件包包括头文件 ...

  5. LISP语言学习资源

    LISP的介绍:Paul Graham 的主页 http://paulgraham.com/index.html Lisp之根源 - 保罗·格雷厄姆 http://daiyuwen.freeshell ...

  6. RTT设备与驱动之PIN设备

    单片机的PIN有2个基本功能:GPIO和AFIO,其中gpio的常用功能: 1 输入:上拉.下拉.模拟.浮动 2 输出:上拉.下拉.推挽.开漏 3 中断:上升沿.下降沿.双沿.高电平.低电平触发 RT ...

  7. maya卸载不干净

    AUTODESK系列软件着实令人头疼,安装失败之后不能完全卸载!!!(比如maya,cad,3dsmax等).有时手动删除注册表重装之后还是会出现各种问题,每个版本的C++Runtime和.NET f ...

  8. 性能测试工具LoadRunner12-LR之Virtual User Generator 脚本编写验证步骤以及LR常见错误处理方法

    验证脚本比较好的流程: Generate:录制或开发脚本 SUSI(Single User Single Iteration,单用户单循环):运行录制生成的脚本,解决可能存在的关键问题 SUMI(Si ...

  9. [转]关于Jquery的DataTables里TableTools的应用

    本文转自:http://147068307.iteye.com/blog/1700516 最近在产品中使用了TableTools这个工具,主要用来实现导出和复制功能. 但是在实际的运用中出现了以下相关 ...

  10. GitKraken使用教程-基础部分(2)

    3. 修改用户名 为了方便项目中代码的管理,需要重新编辑用户名. 点击右上角的图像即可看到如下图 3‑1所示的下拉菜单,鼠标悬于Profile上,会出现一个Edit按钮. 图 3‑1 编辑个人信息 点 ...