删边

删边

  昨天$asuldb$问了我一道题,那道题很神奇.要动态的维护一棵最小生成树,有时还需要删掉一些边,这就出现了一系列的问题.因为总的边数非常多,删边的时候如果使用所谓的"惰性删除",也就是打一个标记表示这条边被删掉了,就会极大地降低效率,因为每次在生成树上找环时会访问很多的无效边,所以必须动态地删除才可以,可是...网上似乎没有这方面的资料?

  图论中有删除操作的不多,比较典型的就是欧拉回路中走过去要删掉,但是那种做法似乎不是很适合这道题...还有$LCT$

  有一种最简单的方法:邻接矩阵存图,可以非常方便的实现$O(1)$删除,而且删反向边也极其简单.$g[x][y]=g[y][x]=0$.不过这种方法的局限性也是非常明显的,毕竟大多数图论题的图都是比较稀疏的,空间也开不下.

  另一种比较$C++$的方法:采用$vector$存边,可以做到$O(N)$的删除,对于那道题来说就很够用了,因为每次在树上$dfs$也已经有了$O(N)$的复杂度.

  但是!经过一节课的修改和试验,我发现了一种真正的$O(1)$删边方法,而且非常的简单,还可以删相应的反向边,这一点第二个做法似乎是做不到的.这种方法是基于链式前向星存图的,因为这种做法本质上就是$N$个链表来存边,而链表的删除就是常规操作了.注意如果当前的边是这个点发出的第一条边要特殊处理一下.所以这个为什么想了一节课...突然发现真的好简单啊...

  关于反向边的删除:其实非常的简单,就是利用网络流的技巧,边集数组从$0$开始计数,那每条边相对应的反向边就是$iquad xorquad  1$.用一样的方法删掉就好啦.

  刚刚想到的奇怪做法:依旧使用惰性删除,但是每加入$m$条边就将所有边删去进行重构,有点像替罪羊树的感觉(虽然我不会),可能也可以将复杂度保持在一个看得过去的复杂度上.

  
 1 void add (int x,int y)
 2 {
 3     t[++h].too=y;
 4     t[h].fro=x;
 5     t[ firs[x] ].pre=h;
 6     t[h].nex=firs[x];
 7     firs[x]=h;
 8 }
 9 
10 void del (int id)
11 {
12     if(t[id].pre)
13     {
14         t[ t[id].pre ].nex=t[id].nex;   
15         t[ t[id].nex ].pre=t[id].pre;
16     }
17     else
18     {
19         firs[ t[id].fro ]=t[id].nex;
20         t[ t[id].nex ].pre=0;
21     }
22 }
23 
24 void print_ed()
25 {
26     printf("
");
27     for (R i=1;i<=n;++i)
28     {
29         printf("%d->",i);
30         for (R j=firs[i];j;j=t[j].nex)
31             printf("%d ",t[j].too);
32         printf("
");
33     }
34     printf("
");
35 }
删边

 

  ---shzr

原文地址:https://www.cnblogs.com/shzr/p/9798202.html