基环树也可以直接套强连通缩点给秒了,但是事实上假如不需要缩点的话有更简单的写法。
下面是一种示例,必须是内向基环树,注意内向基环树的dfs上面有好几个时点:
0、进入环的时候,有时是从入度为0的点进入可能会有特殊操作,但是一般来说进入的时候主要是各个操作的初始化值。
1、当 color[u]!=0&&color[u]==c 时,第一次找到环的入口,可以这时候处理入口的值,但一般只交给3去做就好了。
2、当 color[u]!=0&&color[u]!=c 时,意味着找到其他dfs找过的点,有可能是环的其中一个入口,也有可能是树分叉,因为不是从入度为0的点开始找的甚至可能本身是一条链,这个时候处理不在环中的操作(op1)。
3、当 incirle 时,意味着在环中,处理在环中的操作(op2)。当 u==incirle 时,从环的入口退出,把在环中的标记清空,并处理退出环的操作(op3)。
4、以上都不是,意味着不在环中,处理不在环中的操作(op1)。
总之大概是这个样子,基环树也并不是都要存入度的,很多情况是可以直接用op1来继承,而且op1是躲不开的,因为有时候树会分叉。
const int MAXN = 2e5;
int n, G[MAXN + 5];
int color[MAXN + 5], cntcolor;
int incircle;
void dfs(int u, int c) {
if(color[u]){
if(color[u] == c){
incircle = u;
return;
}
//op1
return;
}
color[u] = c;
dfs(G[u], c);
if(incircle) {
//op2
if(u == incircle) {
//op3
incircle = 0;
}
}
//op1
}
void test_case() {
scanf("%d", &n);
for(int i = 1; i <= n; ++i)
scanf("%d", &G[i]);
cntcolor = 0;
for(int i = 1; i <= n; ++i) {
if(!color[i]) {
++cntcolor;
//op0
dfs(i, cntcolor);
}
}
}
但是还是希望使用缩点法,缩点法没有这么多时点,全部都是建新图。
原文地址:https://www.cnblogs.com/KisekiPurin2019/p/11980305.html
时间: 2024-10-12 23:19:14