The man who has done Oi is probably not a stranger to Tarjan. This man invented a lot of magical algorithms, which were adopted extensively in the Oi session.
His most widely used three algorithms are related to $dfn$, $low $.
To find strong connected components in a graph
In fact, to say the point, is to shrink point. The more you use is to turn a directed ring graph into a dag. Then some common problems are solved by using some of the magical properties of the DAG.
The core code is as follows:
void Tarjan (int node) { vis[node]=1;dfn[node]=low[node]=++dfs_clock; Stack[++top]=node; for (int i=link[node];i;i=e[i].next) if (!dfn[e[i].y]) { Tarjan (E[I].Y); Low[node]=min (Low[node],low[e[i].y]); } else if (Vis[e[i].y]) low[node]=min (Low[node],dfn[e[i].y]), if (Dfn[node]==low[node]) {Group_num++;int tmp;do{ Tmp=stack[top--];vis[tmp]=0;group[tmp]=group_num;} while (Tmp!=node);}}
After each execution, the $group $ value is the same as in the strongly connected component. At the same time $group_num$ also represents a few strong connected components here.
It is important to note that this applies only to the indented map of the graph. If we use this as a template for the father and then the delusion of the image to shrink into a tree is a big mistake, as to the direction of the graph of the contraction point, please refer to the following points of the double Unicom component
non-direction graph for cutting point/cutting edge
The cut point and cutting edge is actually no difference, if a point exists on a side for cutting edge, then this point must be cut point.
Accordingly, for the point $node$ son $son$, if $dfn[node] \leq Low[son] $, then $edge_{(Node,son)}$ is a cutting edge, and $node$ is the corresponding cut point.
Special, if the $node$ is $root$, and only one son, also satisfies the above conditions, but obviously $node$ is not cut point, all need special sentence.
void Tarjan (int node,int father) { vis[node]=1;dfn[node]=low[node]=++dfs_clock; for (int i=link[node];i;i=e[i].next) if (e[i].y!=father) { if (!dfn[e[i].y]) { outdu[node]++; Tarjan (E[i].y,node); Cmin (Low[node],low[e[i].y]); if (Low[e[i].y]>=dfn[node]) ok[node]=1; } else if (Vis[e[i].y]) cmin (Low[node],dfn[e[i].y]); } if (outdu[node]==1&&node==1) ok[node]=0;}
The non-direction graph seeking point double unicom component
This piece is relatively complex and can be used to do a problem. What is the point of dual-link components? The straightforward point is a "circle" from one point to another.
It was mentioned that the method of finding strong connected components could not be used to make a graph shrink into a tree, so you can refer to this picture.
If you only use that method, the whole picture will be shrunk to a point, but it is obvious that the graph should be two points of double connectivity.
It can be noted that the point connecting two points is a cut point , so you can use the previous ideas to solve the solution point of the dual-link component.
void Tarjan (int node) { dfn[node]=low[node]=++dfs_clock; Stack[++top]=node;int son=0; Auto (I,node) if (!dfn[e[i].y]) { Tarjan (E[I].Y); Cmin (Low[node],low[e[i].y]); if (Low[e[i].y]>=dfn[node]) { int tmp;group_num++; do{ tmp=stack[top--]; GROUP[GROUP_NUM].PB (TMP); } while (TMP!=E[I].Y); GROUP[GROUP_NUM].PB (node); } } else Cmin (Low[node],dfn[e[i].y]);}
At first glance it seems that there is no difference between finding a strong connected component, indeed. This just moves the process we call the pinch to the loop.
It's not exactly the same as the first build of a new map. For each point, a new point is created, and the point is connected to each point in the dual-link component. It will eventually make a tree, and the points (except the imaginary points) contained in the path between any two points in the tree are the points that must be made on the original.
Tarjan Three Knives