整理的算法模板合集: ACM模板
基环树
基环树(基于环的树 ),也是环套树,是一种有 n n n 个点 n n n 条边的图,简单地讲就是树上在加一条边。它形如一个环,环上每个点都有一棵子树的形式。
基环内向树:每个点出度为1(因此每个环上点的子树,儿子指向父亲)
基环外向树:每个点入度为1(因此每个环上点的子树,父亲指向儿子)
基环树的关键就是找到环,可以先把环当作这个无根树的 “根” ,也就是把环当成一个点(先不管它),这样一颗基环树就变成了一个普通的树,然后我们先按照解决普通树的方法对“根”的所有子树依次处理求解答案,最后在单独对环上所有的点进行操作求解最终答案即可。
找环的两种方式
拓扑排序
处理无向图
可以找出环上的所有点。
void topsort(){
int l=0,r=0;
for (int i=1;i<=n;i++)
if(in[i]==1) q[++r]=i;
while(l<r) {
int now=q[++l];
for (int i=ls[now];i;i=a[i].next){
int y=a[i].to;
if(in[y]>1){
in[y]--;
if(in[y]==1) q[++r]=y;
}
}
}
}
之后入度 > = 2 >=2 >=2 的点就是环上的点
dfs
处理有向图,码量小
void check_c(int x)
{
v[x]=true;
if(v[d[x]]) mark=x;//环上的一点
else check_c(father[x]);
return;
}
我们稍加修改就可以保存所有的环上的节点了。
inline bool dfs(int x, int in_edge)
{
if(v[x] == 1){
//再次访问说明到了环的链接点,标记它是环(v[x] = 2)
v[x] = 2, loop[++ cnt] = x, v2[x] = 1;
return true;
}
v[x] = 1;
for(int i = head[x]; ~i; i = nex[i]){
int y = ver[i];
//如果当前边不是上一条边(没有往回走)并且当前节点在环上
if(i != ((in_edge) ^ 1) && dfs(y, i)){
//每次存一个点,靠继续dfs遍历整个环
if(v[x] != 2)//当前节点不是衔接点,把环里的点存起来
loop[++ cnt] = x, v2[x] = 1, s[cnt] = s[cnt - 1] + edge[i];
else {
//环的链接点
s[st - 1] = s[st] - edge[i];//又转回来(破环成链)
return