Elementary Graph Theory Full Solution

This article moved this article , but MARKDOWN reworked it. It is recommended to read the original.
Relocation purpose: To promote the above article and help more people.

basic definition

Edge-derived subgraph: A graph composed of several edges and all vertices connected by these edges is called an edge-derived subgraph.
Point-derived subgraph: A graph composed of several points and all edges whose ends are in the point set is called a point-derived subgraph.
Closed subgraph: defined on a directed graph.
A closed subgraph derived from a point set V is
a point-derived subgraph of all points reachable by V. Its precise definition is that if x
is in the subgraph, then
all outgoing points and outgoing edges of x are in the subgraph of the original graph; it is equivalent to that all points that each point can reach are in the subgraph.

1. Shortest route

The shortest path is the most basic class of problems in graph theory.

The following notation disu means the shortest path
from the source point to node u , n is the number of nodes |V| , and m is the number of edges |E| .




1.1 Bellman-Ford

Bellman-Ford is a very violent method of finding the shortest path (BF is to dijkstra as FF is to dinic).

A round of relaxation is called as updating disv
with disu+wu,v for each edge (u,v) . We assert that the shortest path of at least one node is updated in each round, and it is enough to relax for n−1 rounds.


Proof of correctness: Let the source point be 1
. In
the shortest path 1→p1→⋯→u of 1→u
, for each node pi
, 1→p1→⋯→pi
must also be
the shortest path of 1→pi. So the shortest path of one node must be extended by the shortest path of another node. Because the shortest path has at most n−1
edges, and the i-th round of relaxation will get the shortest path
with the number of i edges , so at most only n−1 rounds of relaxation are needed.

The algorithm can also determine whether a negative cycle exists on a graph.
If the shortest path of the node is still updated in the nth round of relaxation, then there is a negative cycle in the graph.

The time complexity of the algorithm is O(nm)
.

1.2 Dijkstra

Dijkstra is a greedy shortest path algorithm for non-negative weight graphs.

The extended node u is called all outgoing edges (u,v)
for u , and disv is updated with disu+wu,v .



Among the nodes that have obtained the shortest path, take out
the node that is closest to the source point (that is, the smallest dis) that has not been expanded and expand it. Because there is no negative weight edge, the shortest path length of the extracted nodes does not decrease monotonically.

How to judge that a node has taken the shortest path? In fact, there is no need to judge, and the node taken out each time has just taken its shortest path. According to non-negative edge weights and Dijkstra's greedy algorithm flow, this can be proved by induction and contradiction.

Inductively assume that the nodes p1, p2,...,pk−1 that have been expanded
all get their shortest path during expansion. pk is the smallest node of
dis that has not been expanded .


The shortest path of pk must
be extended from the shortest path of pi(1≤i<k), and dis(pi)+w(pi,pk+1)+w(pk+1,pk)<dis(pj) cannot appear )+w(pj,pk)(1≤i,j<k)
. Otherwise, since the edge weight is non-negative, w(pk+1,pk)≥0
, so dis(pi)+w(pi,pk+1)<dis(pj)+w(pj,pk),
that is, the current dis(pk +1)<dis(pk) , which contradicts the minimum of
dis(pk) .

Initially let the dis of the source point
be 0
, the assumption is true, so the algorithm is correct.


The process of taking out the node with the smallest dis can be maintained by the priority queue priority_queue. Every time u is expanded
, if disu+wu,v<disv
, then (v,disu+wu,v)
, which is the node number and its updated dis,
will be thrown into the priority queue as a two-tuple. When trying to extract a node, use disu+wu,v
as the key to extract the smallest two-tuple, then its corresponding node number is the node we are looking for.

Note that a node may have multiple incoming edges and enter the priority queue multiple times. But when it is taken out for the first time, it must be the shortest path. For this, it is necessary to record vis[i] indicating whether a node has been expanded. If the currently fetched node has already been expanded, ignore it. It can also be judged whether there is a dis in which the second element of the current two-tuple is equal to the first element (node ​​number)
. If not, it means that the current node has been expanded. Otherwise the complexity will degenerate to m2logm
.

The time complexity of the algorithm is O(mlogm)
.

P4779 template question code.

#include <bits/stdc++.h>
using namespace std;
#define pii pair<int, int>
const int N = 1e5 + 5;
int n, m, s, dis[N];
vector<pii> e[N];
int main() {
    
    
  cin >> n >> m >> s;
  for(int i = 1; i <= m; i++) {
    
    
    int u, v, w;
    scanf("%d%d%d", &u, &v, &w);
    e[u].push_back(make_pair(v, w));
  }
  memset(dis, 0x3f, sizeof(dis));
  dis[s] = 0;
  priority_queue<pii, vector<pii>, greater<pii>> q; // 优先取权值较小的 pair
  q.push(make_pair(0, s)); // 注意第一关键字要放到前面
  while(!q.empty()) {
    
    
    auto t = q.top();
    q.pop();
    int id = t.second; // 不要搞反了,编号是 second
    if(t.first != dis[id]) continue;
    for(auto _ : e[id]) {
    
    
      int it = _.first, d = t.first + _.second;
      if(d < dis[it]) q.push(make_pair(dis[it] = d, it));
    }
  }
  for(int i = 1; i <= n; i++) cout << dis[i] << " ";
  return 0;
}

1.3 SPFA and Negative Loop

Regarding the SPFA, ___.

SPFA is essentially Bellman-Ford for queue optimization.

When relaxing node x,
find the point that may be relaxed next, that is,
the point adjacent to x and the shortest path is updated, and push it into the queue. In addition, recording whether a point is in the queue and not pushing it if so can significantly reduce the constant.

There is no difference in time complexity compared to BF, still O(nm)
. It is very efficient on general graphs, but it can be squared by special data cards, so SPFA is not recommended when dijkstra can be used.

Note that if SPFA is used to solve the point-to-point shortest path (cost flow EK), the algorithm cannot end when the queue head is the target node. Because a node enters the queue, it does not mean that it has taken the shortest path.

SPFA Negative Ring: If a node enters the queue more than n−1
times (note that it is not relaxed, because a node is relaxed does not mean entering the queue), or the number of the shortest path is greater than n−1
, then there is a negative node in the entire graph. ring. For the latter, the record li represents the shortest path length
from the source point to i , and the relaxation time is lv←lu+1 and it is enough to judge whether there is lv<n .


The number of enqueues is slower than the shortest path length, so the latter is recommended.

P3385 template question code.

#include <bits/stdc++.h>
using namespace std;
const int N = 2e3 + 5;
int n, m, dis[N], len[N], vis[N];
vector<pair<int, int>> e[N];
void solve() {
    
    
  cin >> n >> m;
  for(int i = 1; i <= n; i++) e[i].clear();
  for(int i = 1; i <= m; i++) {
    
    
    int u, v, w;
    cin >> u >> v >> w;
    e[u].push_back(make_pair(v, w));
    if(w >= 0) e[v].push_back({
    
    u, w});
  }
  queue<int> q;
  memset(dis, 0x3f, sizeof(dis)); // dis 的初始值需要赋成 0x3f
  memset(vis, 0, sizeof(vis)); // 清空 vis =.=
  q.push(1), len[1] = dis[1] = 0; // 读题,从顶点 1 出发 =.=
  while(!q.empty()) {
    
    
    int t = q.front();
    q.pop(), vis[t] = 0;
    for(auto it : e[t]) {
    
    
      int d = dis[t] + it.second, to = it.first;
      if(d < dis[to]) {
    
    
        dis[to] = d, len[to] = len[t] + 1;
        if(len[to] == n) return puts("YES"), void();
        if(!vis[to]) vis[to] = 1, q.push(to);
      }
    }
  }
  puts("NO");
}
int main() {
    
    
  int T;
  cin >> T;
  while(T--) solve();
  return 0;
}

1.4 Johnson

Prerequisite knowledge: Bellman-Ford & Dijkstra.
Johnson's algorithm is used to solve the all-source shortest path problem with negatively weighted edges. The so-called all-source shortest path problem is to solve the shortest path between any two points on the graph.

The ingenuity of Johnson's algorithm is to assign potential energy hi to each point
. Just like the potential energy in the physical sense, starting from one point and arriving at another point, no matter what path you take, the total amount of change in the potential energy is certain. The physical reality inspires us to set
the new weight w′u,v of the edge (u,v)
to wu,v+hu−hv
.

Consider a path S→p1→p2→⋯→T
whose original length is

L(S→T)=wS,p1+wp1,p2+⋯+wpl, the
new length of T is

L′(S→T)=(hS+wS,p1−hp1)+(hp1+wp1,p2−hp2)+⋯+(hpl+wpl,T−hT) After simplification, it is not difficult to see that L(S→
T )=L′(S→T)+hT−hS
. For fixed S,T
, the path of the original graph corresponds to the new graph, and the length increases by hS−hT
. This has nothing to do with which nodes the path passes through, but only with S,T
. Therefore, the shortest path from S→T on the original graph
is still the shortest path on the new graph.

Next, consider solving the original problem.

Due to the negative weights, we cannot solve for the shortest path using dijkstra. The time complexity of multiple SPFA or BF is not excellent. Try to apply the above analysis to assign a reasonable value to each point, thereby eliminating all negative weight edges on the graph.

To make w′(u,v)≥0
, only w(u,v)+hu≥hv is required
. What's this? Triangle Inequality! If there is no negative cycle in the initial graph, then we must be able to continue to relax and finally obtain such a h
. Specifically, initially set all h
equal to 0
, and then use the BF algorithm to perform n−1
rounds of relaxation.

The relaxation must end after n−1
rounds, otherwise it means that there is a negative cycle in the original graph, because the above operation is equivalent to establishing a virtual point 0 and connecting
an edge with an edge weight of 0 to all nodes
, and finding
the shortest path from 0→i Road hi
.

After the operation, we update the weight of each edge w′(u,v)=w(u,v)+h(u)−h(v)
. According to the initial analysis, the shortest path between the obtained new graph and any two points in the original graph remains unchanged, and there is no negative edge weight, and n rounds of
ijkstra can be used to solve the shortest path between any two points.

Finally, don't forget to
add hv−hu to the shortest path of u→v
.

The time complexity of the algorithm is O(nmlogm)
.

Template question P5905 code.

#include <bits/stdc++.h>
using namespace std;
#define pii pair<int, int>
const int N = 3e3 + 5;
int n, m, h[N], dis[N];
vector<pii> e[N];
int main() {
    
    
  cin >> n >> m;
  for(int i = 1; i <= m; i++) {
    
    
    int u, v, w;
    cin >> u >> v >> w;
    e[u].push_back(make_pair(v, w));
  }
  for(int i = 1; i <= n; i++) {
    
    
    bool found = 0;
    for(int j = 1; j <= n; j++)
      for(auto it : e[j])
        if(h[j] + it.second < h[it.first])
          found = 1, h[it.first] = h[j] + it.second;
    if(i == n && found) puts("-1"), exit(0);
  }
  for(int i = 1; i <= n; i++) {
    
    
    long long ans = 0;
    for(int j = 1; j <= n; j++) dis[j] = i == j ? 0 : 1e9;
    priority_queue<pii, vector <pii>, greater <pii>> q;
    q.push(make_pair(0, i));
    while(!q.empty()) {
    
    
      auto t = q.top();
      q.pop();
      int id = t.second;
      if(t.first != dis[id]) continue;
      for(auto _ : e[id]) {
    
    
        int it = _.first, d = t.first + h[id] - h[it] + _.second;
        if(d < dis[it]) q.push(make_pair(dis[it] = d, it));
      }
    }
    for(int j = 1; j <= n; j++) ans += 1ll * j * (dis[j] + (dis[j] < 1e9 ? h[j] - h[i] : 0));
    cout << ans << endl;
  }
  return 0;
}

1.5 Floyd and transitive closures

Like Johnson, Floyd can also solve the all-source shortest path problem with negatively weighted edges.

The core of Floyd's algorithm has only four steps: enumerate k
, enumerate i
, enumerate j
, update dis(i,j) with dis(i,k)+
dis(k,j)
.

Pay attention to the enumeration order, the node as the transit point must be enumerated at the outermost layer.
Initially let dis( u,v) between all edged point pairs ( u,v)
be equal to w(u,v)
.

Proofs of correctness are still inductive. Consider
the shortest path u→p1→⋯→pk→v of u→v
. Let pi be the last enumerated point in
p . If dis(u,pi) and dis(pi,v) have taken the shortest path, then dis(u,v) will naturally be correctly updated as the shortest path .



According to the initialization operation,
when the shortest path of the boundary case u→v has only one side, dis(u, v)
takes the shortest path w(u, v)
to be established. By mathematical induction, the hypothesis is established, and the correctness of the algorithm is proved.

The time complexity of the algorithm is O(n3)
. Not only is it easy to write, but it also runs more efficiently than Johnson on dense graphs, so Floyd is also the best choice for the shortest path algorithm when the data size is small.

In addition, Floyd can also seek transitive closure (the author always thought that transitive closure was a verb, but I didn't expect it to be a noun).
The transitive closure of a directed graph G is defined as an n
-order Boolean matrix T
, satisfying that Ti,j is equal to 1
when i
reaches j , and 0 otherwise . Just change the inner layer operation to Ti,j←Ti,j∨(Ti,k∧Tk,j) .



bitset can optimize the complexity of transitive closure to n3w
. For sparse graphs, passing closures after contraction can be done as nmw
.
What? Do you still need code for such a simple thing?

1.6 Examples

I. P5304 [GXOI/GZOI2019] Tourist

An interesting topic.

The core idea of ​​the O(mlogmlogk)
approach is to run the shortest path after binary grouping. Two different numbers must have at least one bit different in binary, and the correctness is guaranteed. You have to drive through O2 in Luogu.

Random grouping is also possible, and
the correctness of doing k times is 1−(34)k
. Similar topics such as CF1314 D.

The idea of ​​the O(mlogm)
approach is ingenious.
Preprocess the shortest distance fi
and corresponding city fri from each special city to point i
, and
the shortest distance gi
and corresponding city toi from point i to all special cities
. For each edge u→v
, if fru≠tov
,
update the answer with fu+wu,v+gv. See the solution of srf for the proof of correctness.

II. P1462 The Road to Orgrimmar

The answer satisfies dichotomy, dichotomy + dijkstra is enough.

Time complexity nlognlogc
.

.P4568 [JLOI2011] Flightline

Note that k
is very small, just record how many free edges are currently used when running the shortest path, this is called the shortest path in a hierarchical graph.

Time complexity O(mklog(mk))
.

IV. P7916 [CSP-S 2021] Transportation Planning

k=2
is "the wolf catches the rabbit", and the minimum cut-turn dual graph in the planar graph is the shortest path.


It is similar when k>2 .
After the planar graph is transformed into a dual graph, k nodes will appear in the outermost layer . For a node i
, let its counterclockwise ray color and clockwise ray color be Li
and Ri respectively
, and the value is 0
or 1
, which means white or black. If Li=Ri
, then
it is optimal for two adjacent rays of i to be in the same connected block. Because any scheme that divides them will always reduce the cost after adjusting them to be in the same connected block.

Obviously, (Li, Ri)
is equal to (0,1)
and (1,0)
have the same number of nodes. Each (0,1) matches
each (1,0)
, and all edges that the path passes have different colors at both ends. Therefore, such a matching scheme can always give a partition scheme and its cost.

The key property is that the matching of any two points will not intersect, that is, a<b<c<d will not appear
and a
matches c
, and b
matches d
. If they intersect, the adjustment method can prove that it is not inferior when not crossing.

Therefore, first find out the pairwise shortest paths between all (0,1)
and (1,0) points.
Finding the minimum cost of matching can be similar to parentheses matching. After breaking the ring and forming a chain, the interval DP has a time complexity of O(knmlog(nm)+k3)
.

V. CF1163F Indecisive Taxi Fee

Classic question.

First find
the shortest path of 1→n P=p0(=1)−→e1p1−→e2⋯−→eLpL(=n)
. Let t=(u,v)
.

When t∉P
, the new shortest path will either remain unchanged or pass through this edge. Obviously, forcing
the shortest path through a certain edge (u, v) is equal to the shortest path from 1
to u , plus the shortest path from v to n , plus wt ; or exchange the status of u, v , the two cases take minimum value. Suppose the shortest path from 1 to u is pre(u), and the shortest path from v to n is suf(v) , then the answer can be written as










min(w§,w(u,v)+min(pre(u)+suf(v),suf(u)+pre(v)) When t∈P, the new shortest path is either w§

wt +x , or the shortest path
that is forced not to pass through t (when x≤wt must be the former, but the classification discussion is too troublesome, it is better to take min directly in the two cases ). Now the only problem is transformed into each edge t , Solving for L(t) means forcing the shortest path length not to pass through t.





Consider finding any shortest path trees T1 and Tn starting from 1
and n in the original graph . It is necessary to ensure that the paths between 1 and n on the two trees are equal, that is, if P=T1(1→n) , then P should be equal to Tn(1→n) . This can first calculate T1 and the corresponding P , and then calculate Tn according to P. Obviously, pre(u) is equal to the depth of u on T1 , and suf(v) is equal to the depth of v on Tn .

















Let pr(u)
represent the last intersection point of T1(1→u)
and P
(or, pr(u) is equal to the LCA of n and u on
T1 ), su(v) represents the intersection of Tn(v→n) and P first intersection. From another perspective, pr(u) is the shortest path from 1 to u , and the last node that coincides with the shortest path from 1 to n . The same is true for su(v).











For an
edge (u,v) that does not belong to P
, we try to pass through this edge (both directions are tried, only one direction is discussed below). For u→v
, according to the above analysis, the shortest path is T1(1→u)∪(u,v)∪Tn(v→n)
, and its length is C(u,v)=pre(u)+ w(u,v)+suf(v)
(defining C(e)
means forcing
the shortest path through e).

It is easy to find that the value of C(u,v) can be used to update L(ei) corresponding to all edges ei between pr(u) and su(u) on
all paths P , because C(u,v) corresponds to The path does not pass through these edges. For each edge that does not belong to P, its C value will contribute to a corresponding path on P. Each L(ei) can be calculated by using multiset maintenance for off-line scan lines .









Therefore, for
the case t∈P, the answer is min(w§−wt+x,L(t))
.

etc? Is it a little imprecise? When the author was thinking about this question, one of the biggest problems encountered was how to prove that after removing a certain ei , there must be an edge e′j=(p′j−1,p′j) on
the new shortest path P′ such that ei is between pr(p′j−1) and su(p′j) . This proposition is equivalent to the existence of at least one edge (u, v) on P′ such that the path of 1→u is equal to T1(1→u) , the path of v→n is equal to Tn(v→n) , and ei is not in pr(u ) and su(v) . Its proof is too complicated and omitted. See cf1163f - ycx's blog for details.













VI. P3238 [HNOI2014] Road congestion

Same routine as above.

VII. P3573 [POI2014] RAJ-Rally

Same routine as above.

VIII. P2761 software patch issue

Note that the total number of patches is small, so the states that can be reached from the initial state must not be too many. Soup + SPFA is enough.

2. Differential Constraints

Prerequisite knowledge: Bellman-Ford and SPFA.

2.1 Algorithm introduction

The difference constraint problem is to find the solution of any set of x given several inequalities of the form xa−xb≤c
or xa−xb≥c .

We found that as long as xa and xb
have different signs when they are on one side of the inequality sign, then all constraints can be written as xi+c≥xj
.

The triangle inequality comes up again.
We connect an edge of length c from i→j
, and then connect an
edge of length 0 from the super source point 0 to each point
to prevent the graph from being disconnected (or set all dis=0 at the beginning
and enqueue all points) , run the shortest path, the shortest path length of each point is a set of solutions.

Because generally this c
has a negative value (if it is all non-negative, all the numbers are equal), so use Bellman-Ford or SPFA to find the shortest path. Obviously, if there is a negative cycle, there is no solution.

Time complexity O(nm)
. The template question P5960 code is as follows.

#include <bits/stdc++.h>
using namespace std;
const int N = 5e3 + 5;
int n, m, vis[N], dis[N], len[N];
vector<pair<int, int>> e[N];
int main() {
    
    
  cin >> n >> m;
  for(int i = 1; i <= m; i++) {
    
    
    int u, v, w;
    cin >> u >> v >> w, e[v].push_back(make_pair(u, w));
  }
  queue<int> q;
  for(int i = 1; i <= n; i++) q.push(i), vis[i] = 1;
  while(!q.empty()) {
    
    
    int t = q.front();
    q.pop(), vis[t] = 0;
    for(auto it : e[t]) {
    
    
      int to = it.first, d = dis[t] + it.second;
      if(d < dis[to]) {
    
    
        dis[to] = d, len[to] = len[t] + 1;
        if(len[to] == n) puts("NO"), exit(0);
        if(!vis[to]) q.push(to), vis[to] = 1;
      }
    }
  }
  for(int i = 1; i <= n; i++) cout << dis[i] << " ";
  return 0;
}

2.2 The lexicographic extremum of the solution

Generally speaking, the solution of the differential constraint system does not have the concept of "dictionary order", because we only constrain the difference between variables, and the value of the variable itself can be fixed with the value of a variable, so the solution The lexicographical order can go towards infinity or infinitesimal.

The extremum of the lexicographical order is established on the basis that the variables are bounded. It may be assumed that we want to find
the maximum value of the lexicographic order of the entire differential constraint system when the constraint xi≤0. Note that xi≤0
can be regarded as a triangle inequality (x0=0)+0≥xi
, so we establish a virtual point 0
, assign its initial dis
to 0
, and connect all other variables with weights of 0
(this is equal to Price initially enqueues all points with dis=0
).

We use the triangle inequality when solving differentially constrained systems, converting it into a shortest path problem. This gives it a good property: a set of solutions obtained by SPFA is exactly the lexicographically maximum solution.

First of all, it is clear that for an
edge from u→v whose weight is w(u,v)
, it means to restrict xu+w(u,v)≥xv
.

Consider
the shortest path tree from 0 to each node. For each edge on the tree, xi+w(i,j)=xj is satisfied
. If xi+w(i,j)>xj
, then the whole graph can continue to relax. If xi+w(i,j)<xj
, it means that
the shortest path of j is not
inherited from i, so (i,j )
must not appear as a tree edge.

This shows that
the limit of xi+w(i,j)≥xj on the tree has been filled, and the equal sign has been obtained (xj
cannot be larger, and the limit will be destroyed if it is larger), and each variable has reached its theoretical limit. , naturally get the maximum solution of lexicographical order.

For lexicographically minimal solutions, we restrict xi ≥ 0
. Therefore, all nodes have
an edge w(i,0)=0 towards 0
. The smallest lexicographical order is the opposite of the largest lexicographical order. Therefore, if all variables are considered to be reversed, then all restrictions should be reversed, which means that the
directions (not edge weights) of all edges in the graph (including all newly created edges i→0 ) are reversed. Then find the maximum solution of the lexicographic order, and then take the opposite number.

2.3 Examples

I. P5590 Racing Game

Good question.

To change the way of thinking, instead of setting the edge weight to make the path lengths equal, it is better to set the path length to fit the limit of the edge weight.

Let di be the shortest path of
1→i , just ensure that for all sides (u, v) there is wu, v=dv−du to make any simple path equal in length. So 1≤dv−du≤9 is transformed into du+9≥dv and dv−1≥du , and the difference constraint can be solved. Note that the edges that are not on any path from 1→n are useless. These edges should not be included in the limit, and the weights can be marked casually.






II. P7515 [Provincial Entrance Examination 2021 Paper A] Matrix Game

God question.

Construction questions can consider the adjustment method.

Fix the first row and first column to be all 0
, and
the rest of the matrix ai,j can be deduced only according to the limitation of b
.
Note that after performing −ri,+ri,−ri,+ri,…
operations on each number in the i-th row of the matrix ,
the restriction of b is still satisfied, and the column is the same.
Therefore, if we add (−1)jri+(−1)icj to ai,j
, then 0≤ai,j+(−1)jri+(−1)icj≤106
. However, when i and j
have the same parity,
the symbols before ri and cj are the same, and the occurrence and constraint cannot be handled.

We hope that for each row, the coefficients of ri of any two adjacent positions
are opposite. Do the same for each column. Therefore, considering black and white coloring, the coefficient (−1)i+j+1ri+(−1)i+jcj is obtained
. It is not difficult to find that the previous symbols of ri
and cj
must be different and meet the constraints, and the difference constraint can be used to solve the problem, and the time complexity is O(Tnm(n+m))
.

The topic is a bit stuck, pay attention to the constant. SPFA will run faster if it judges the shortest path length instead of the number of enqueues.

III. P4926 [1007] Double kill measurer

It is not difficult to think of taking logarithms by turning multiplication into addition. Consider building a difference constraint graph for the restriction of no women's clothing. If there is a negative ring, there must be someone wearing women's clothes. For a person i with a fixed score
, let 0 and i
connect to each other with edges whose edge weights are logxi
and −logxi respectively
.

Set a binary, time complexity O(nslogV)
.

IV. [AGC056C] 01 Balanced

Considering 0
as 1
and 1
as −1
, then the restriction on the problem is in the form of a differential constraint.

For the restriction L−1,R
, interconnect
edges of length 0.

For the two adjacent positions i−1
and i
, the title requires |vi−vi−1|=1
. It seems impossible to describe. However, when the restriction becomes |vi−vi−1|≤1 , you can connect edges of length 1 between
i
and i−1 , and maximize the lexicographic order of v (the difference constraint itself has its own lexicographic extremum nature).


We were surprised to find that it is impossible to have vi=vi−1 under the condition of ensuring the largest lexicographical order
. Simulating the process of the shortest path, it can be proved that
the parity of each vi is fixed, and the parity of two adjacent v must be different: the subscript parity of the two points connected by the
0 side is the same (the title guarantees this)
,
and one side has different parity.

The whole process can be imagined as adding some positions to the set S initially
, indicating that their v
value is 0
. Each time consider increasing the current v
value cur
and
extending the extremely long continuous segment of S to the left and right, the v
value of the newly expanded position is equal to cur
. This is because, considering vl−1=vr+1=c
and
the v
value of [l,r] has not yet been determined. We want to maximize
the lexicographical order of v, naturally vl=c+1
, for this reason, vr
must also be equal to c+1
, so as to maximize
the lexicographical order of [l, r], otherwise
the ascending segment starting from l will be become shorter. To understand perceptually, we want to put the ascending segment as far forward as possible, and when the v
values ​​​​at both ends are fixed and equal, one ascending segment must correspond to a descending segment, so in order to stack all the ascending segments to the front, we have to put them at the end. a descending segment.

The idea of ​​this question is quite clever. Although it is a differential constraint, the form is very novel. You need to guess some properties (or, don’t be limited by inherent thinking) to get the final solution.

The edge weight is only 0/1
, considering 01 BFS, the time complexity is O(n+m)
.


If we simply calculate the prefix sum to get v in order to avoid the restriction of |vi−vi−1|=1
, we will build a differential constraint network with negative weight edges. TLE can be solved by SPFA.

code.

V. P3530 [POI2012] FES-Festival

Well, the limit is very differential constraints. After building the map, first run through the negative ring and judge that there is no solution. But how to meet the maximum number of different t
values? Differential constraints obviously cannot solve such problems. Then there will be no more (fog).

Firstly, the strongly connected components are shrunk (see Section 5.2 for details), and different SCCs are independent, because we can make the distance between two SCCs arbitrarily far. The answer inside an SCC is the maximum value of the shortest path between any two points + 1
: only one type of edge increases the shortest path distance, and the edge weight of one type of edge is only 1
, so if
the shortest path of u→v is w
, Then all points on the path from u→v
must have taken
the w+1
values ​​of tu∼tv.

Since the graph is dense, use Floyd's algorithm to find the shortest path between any two points. The answer is the sum of the answers for each SCC.

The time complexity is tripartite.

3. Minimum spanning tree

3.1 Kruskal

Very classic minimum spanning tree algorithm, the foundation of the foundation.

Greedily sort all the edges according to the edge weight from small to large and enumerate each edge in turn. If the two ends of the current edge are not connected, join the edge. Connectivity is maintained by union lookup. Time complexity O(mlogm)
.

Correctness considers the method of proof by contradiction. If there is an edge (u, v)
such that (u, v)∉T and w(u, v) is not the largest weight in the ring formed on T after
adding (u, v) , then break A smaller spanning tree T′ can be obtained by dropping the edge with the largest weight . But this contradicts the greedy strategy, because (u, v) must be enumerated and added to T before the broken edge .





See the first chapter of simple tree theory for kruskal's reconstruction tree. A brief summary is to maintain the merge relationship by creating a virtual point when merging and looking up sets.

3.2 Prim

Learn a little bit.

To maintain V, E
, each time find the edge (u, v) with ∉E and
one end ∈ V
and the other end ∉ V
with the smallest weight
, and add v
to V
, and (u, v)
to E.
The initial V
can contain any node.

Another way to understand is to maintain the weight cv of each node to represent the minimum weight of all edges (v, u) starting
from v , so that u∈V . Each time the point with the smallest weight is taken out and added to V , the edge weight of the minimum spanning tree is added to cv , and all outgoing edges of v are used to update the weights of all points not in V.






The process of "taking out the point with the smallest weight" can be implemented through a priority queue, similar to Dijkstra's algorithm. Therefore, the time complexity of the algorithm is O(mlogm)
.

3.3 Boruvka

Boruvka's method of finding the minimum spanning tree is rather magical.

Consider several points. For each point, if you want to connect it with an edge, then the edge with the smallest edge weight among its neighbors must be selected. This can be proved by proof by contradiction.

Therefore, for each point, find the edge with the smallest edge weight connected to it. Add all these edges to the minimum spanning tree. Removing at most n2
multiple edges, each edge will make the number of connected blocks −1
, so one such process can strictly reduce the number of connected blocks by half. In this way,
the MST can be obtained by continuing the above process for the remaining connected blocks at most log2n rounds. Note that when selecting the edge with the smallest edge weight, the edge whose two ends are already in the same connected block cannot be selected.

The time complexity of the algorithm is O(mlogn)
.

Boruvka is very useful in solving certain classes of minimum spanning tree problems.
It is in the form of a complete graph with n points given , and the information between two points can be obtained by some kind of calculation. n
is generally at the 105
level.

3.4 Examples

I. P4180 [BJWC2010] Strictly second smallest spanning tree
First, kruskal finds the minimum spanning tree, then enumerates all edges (u, v) , and uses it to replace the largest or strict second largest weight between
u and v on the minimum spanning tree
side. Strictly second largest is required because the largest value may be
equal to wu,v. Time complexity linear logarithmic.

code.

*II.
Interesting application of CF888G Xor-MST Boruvka.

Based on the XOR and the minimum value, it is not difficult to think of
building a 01 Trie for ai. For
all the nodes Vp contained in the subtree of a certain state p on the 01 Trie
, it is obvious that they are already connected internally, because the cost of connecting Vp
to the
node Vq represented by other state q across this state is greater than the cost of connecting within Vp. side price. This is because when crossing an edge, according to the nature of XOR, the cost has a value in the corresponding bit of p or its high bit, but when connecting an internal edge, the corresponding bit of p and its high bit have no value.



So, consider computing the answer. If
both the left and right sons of p have nodes, then an edge needs to be connected between Vlsp
and Vrsp to make Vp connected. Enumerate all values ​​v in Vlsp and find the XOR and minimum weight u with v in the subtree of rsp (01 Trie basic operation), then minu⊕v is the edge connection cost.







Since a node
is enumerated as lsp at most logV
times, the time complexity is strictly nlog2V even without heuristic merging
. After using the heuristic, you can change a logV
into logn
, which is actually useless.

4. Undirected graph connectivity

The following two chapters are related to the tarjan algorithm. Father Tarjan is a god.

The connectivity of undirected and directed graphs is an important part of graph theory.

4.1 Related definitions

Related terms for undirected graph connectivity are cut vertex and cut edge (bridge).

The definitions of the two are very similar, which are nodes or edges that increase the number of connected components after deletion, and they are both definitions on undirected graphs. Obviously, neither an isolated point nor the only second endpoint of an undirected graph consisting of only one edge is a cut vertex, but the only edge of the latter is a cut edge.

Note that Baidu Encyclopedia defines cutting edges on undirected connected graphs. This is imprecise. The cut edges of a disconnected graph are the union of the cut edges of each of its connected components.

The concept corresponding to a cut point is a point biconnected graph, which is defined as an undirected connected graph without a cut point. According to the definition of cut points, both isolated points and point pairs connected by an edge are regarded as vertex biconnected graphs. A maximal vertex biconnected subgraph of a graph is called a vertex biconnected component (V-BCC).

The concept corresponding to cut edges is edge biconnected graph, which is defined as an undirected connected graph with no cut edges. According to the definition of cut edges, isolated points are edge-biconnected graphs, but pairs of vertices connected by an edge are not edge-biconnected. A maximal edge-biconnected subgraph of a graph is called an edge-biconnected component (E-BCC).

Since "there is no cutting edge" means that for any two different nodes u
and v
, there is no necessary edge between them. Therefore, after deleting any u→v
path, u and v
are still connected. This means that any edge belongs to at least one simple cycle (here, a simple cycle is defined as a cycle without repeated edges). Similarly, if every edge belongs to at least one simple cycle, it is easy to prove that the graph is biconnected. We obtain an equivalent determination that an undirected connected graph is an edge biconnected graph: any edge belongs to at least one simple cycle.

Shrink point is a common algorithm in the OI world. Simply put, it is to shrink a certain type of connected components into a point according to equivalence or independence. The original edge connecting two different connected components becomes the one formed by connecting their shrink points. two points. According to the different types of connected components, shrink points can be divided into edge biconnected component shrink points on undirected graphs, point biconnected component shrink points, and strongly connected components (SCC) on directed graphs that will be introduced in Chapter 5 shrink point.

A tree can be obtained after shrinking both edge double and point double points, and a directed acyclic graph can be obtained after SCC shrinks points.

4.2 Tarjan's Algorithm for Cut Points

Next, we will introduce tarjan's method of finding cut points.

The author defaults that readers already understand the dfs tree and dfs order, so I won't repeat them. Make an explanation: the dfs order represents the node sequence obtained by depth-first search of a tree, and the timestamp dfn represents the position of each node in the dfs order. These two concepts need to be distinguished.

The author hopes to propose a new way of understanding the tarjan algorithm. When many blogs on the Internet explain the algorithm, the low array seems to appear out of thin air. The abstract definition confuses many beginners. The incompleteness of the logical chain from asking questions to solving them makes us unable to feel what kind of inspiration it is. prompted the birth of this algorithm.


Define the subtree of node x to indicate the subtree of the node on the dfs tree, including the node itself, denoted as T(x)
.

4.2.1 Cut point judgment rule for non-root nodes

The following discussion is based on the fact that x
is not the root node of the dfs tree of the current connected component.

For T(x)
, if there is a node y∈T(x)
satisfying that all points that y can reach
without passing through x are trapped in T(x) , then x is a cut point, because after deleting x, y and T Nodes outside (x) (since x is not a root, so nodes outside T(x) exist) are not connected, and the number of connected components increases; otherwise, each y is connected to the outside of T(x) , so the entire connected component is still connected .










How to express " all points that can be reached without passing through x are trapped in T(x)
"?

Consider playing tricks on the timestamp corresponding to the dfs sequence.
Note that the timestamp dy(y∈T(x)) of all points in T(x)
is not less than dx
, so the design state fx
represents
the minimum value of the timestamp of a node that x can only reach through a non-tree edge ( Note that f
is not a low array).

Why "only through a non-tree edge": a cut point may exist in multiple points, for the node y at the bottom of a "8"-shaped structure, it can turn up to the node in the middle of the structure through a non-tree
edge x
, and then take a non-tree edge to turn to the node u at the top of the structure
, so
it is illegal to find whether x is a cut point, because fy is updated by the point u that can only be reached through x starting
from y , which does not meet the The "without x " assumption. Only passing through a non-tree edge ensures that the fy we obtain is the minimum value of the timestamp of the node that y can directly reach without passing through the intermediate point.





As an aside, this actually explains why we update low[u] with dfn[v] instead of low[v] for
neighbor v that u has visited and is on the stack .

Consider
all sons y1,y2,⋯,yc of x on the dfs tree
, arranged in order of access. There is no yi≠yj
so that there is a connection between their subtrees. Otherwise, in the process of dfs, if i<j, when
accessing
the subtree of yi, you can directly access
the subtree of yj, so when yj
visits yi
Being visited contradicts that yj
is the son of x
in the dfs tree. This illustrates
the independence between the various sons of x. In other words, for an undirected graph, any two points connected by non-tree edges must be an ancestor-descendant relationship on the dfs tree. This is an important guarantee for the correctness of tarjan's algorithm on undirected graphs. The reader needs to fully understand this property, which will be repeated below.

Since T(yi) is internally connected, when
x is deleted, the connectivity of each node inside T(yi) is the same as that outside T(x) . That is to say, either all nodes of T(yi) are connected with T(x), or none of them are connected. This shows the equivalence of the internal nodes of the subtree T(yi) of some son of x .






Therefore, for
each son yi of x, if there is a point inside
T(yi) that makes it reach a node outside T(x) without passing through x , then T(yi) and T(x) are externally connected after deleting x . We hope that there exists yi such that it does not satisfy such a condition.






First consider using known information to describe "
there is a point p inside T(yi)
so that it
can reach
nodes outside T(x) without passing through x". If p∈T(yi) exists
such that there is a
path p→p1→p2→⋯→pc→q that does not pass through x
, satisfying
that q is the first node outside T(x) on the path
(according to independence, p
and pi
are all in T(yi)
), if and only if pc
can jump out of T(x) through a non-tree edge
.

This means that if there exists p∈T(yi) such that it can reach a node outside T(x)
without going through x , then consider its first path to a node q outside T(x) without going through x , and finally One step makes it jump from inside T(yi) to outside T(x) . Since q is visited before x (otherwise q becomes a node of T(yi) when visiting yi ), dq<dx . This means that there must exist a corresponding pc∈T(yi) such that fpc<dx .














Conversely, if there exists p∈T(yi)
such that fp<dx
, then
there is a point in T(yi) so that it
can reach
nodes outside T(x) without passing through x. p
is one such node.

In this way, we have proved
the rule for determining that x is a cut point:

If and only if there is a tree edge x→y
such that there is no node u in the y
subtree
such that fu<dx
, x
is a cut point.


This is equivalent to fu≥dx for all u∈T(y)
, ie minu∈T(y)fu≥dx
.

To this end, it is only necessary to record an array gx
representing the minimum value of fu of
all nodes u∈T(x) in the subtree of x , and then judge whether each node is a cut point in linear time.

fu is equal to the minimum value of dv corresponding to all ancestral edges (u, v) of
u on the dfs tree and du takes min .




Note that v
is not the parent of u
on the dfs tree, because (u, v)
is the edge of the tree at this time. If this point is ignored, the result will not be affected when solving the cut point (judgment is minfu≥dx
, with an equal sign), but the judgment will be wrong when solving the cutting edge (judgment is minfu>dx
, without an equal sign). This is mentioned again when solving for cutting edges.
That is, fu=min(du,minv∈anc(u)∧(u,v)∈Edv)
, and gu=minv∈T(x)fv
, according to tree dynamic programming,

gu=min(fu,minv∈son(u)gv)
In summary, we can deduce

gu=min(du,minv∈anc(u)∧(u,v)∈Edv,minv∈son(u)gv)
gu
is representative of u
.

The three expressions separated by commas correspond to:

Initialize low[u] to dfn[u].
For u's
ancestor v on the dfs tree
, update low[u] with dfn[v]. Because it is an undirected edge, for any (u,v)∈E
, as long as v
has been visited before, then v
must be the ancestor of u on the dfs tree
(considering the method of proof, if it is not an ancestor-descendant relationship, for lca(u,v)
applies subtree independence to derive a contradiction). For a neighbor v of
u that has not been visited , search for v and backtrack. This means that v is a child of u in the dfs tree . So update low[u] with low[v]. This is the famous Tarjan algorithm.





4.2.2 Root node

Don't forget that there is also the case where x
is the root node.

At this time, if x
has more than one son in the dfs tree, then according to the independence of the subtrees, after removing x, the
subtrees of each son are not connected and the number of connected blocks increases, so x
is the cut point. Conversely, it is easy to prove that x
is not a cut point.

In summary,
the time complexity of using the tarjan algorithm to solve all cut points on the directed graph G is O(n+m)
. The code for template question P3388 is as follows.

The author emphasizes again that the following code is only correct when solving for cut points. Solving the cutting edge requires additional special judgment, the reason has been analyzed above.

#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 5;
int n, m, root, dn, dfn[N], low[N], cnt, buc[N];
vector<int> e[N];
void dfs(int id) {
    
    
  dfn[id] = low[id] = ++dn;
  int son = 0;
  for(int it : e[id]) {
    
    
    if(!dfn[it]) {
    
    
      son++, dfs(it), low[id] = min(low[id], low[it]);
      if(low[it] >= dfn[id] && id != root) cnt += !buc[id], buc[id] = 1;
    }
    else low[id] = min(low[id], dfn[it]);
  }
  if(son >= 2 && id == root) cnt += !buc[id], buc[id] = 1;
}
int main() {
    
    
  cin >> n >> m;
  for(int i = 1, u, v; i <= m; i++) cin >> u >> v, e[u].push_back(v), e[v].push_back(u);
  for(int i = 1; i <= n; i++) if(!dfn[i]) root = i, dfs(i);
  cout << cnt << endl;
  for(int i = 1; i <= n; i++) if(buc[i]) cout << i << " ";
  return 0;
}

4.3 Edge cutting

4.3.1 Tarjan method

The idea of ​​​​Tarjan's algorithm for finding cutting edges is similar to the idea of ​​​​solving cutting points.

Try to find a necessary and sufficient condition for an edge to be a cutting edge.

First of all, if an edge is a non-tree edge, then cutting it obviously does not affect the connectivity, because the tree edge makes the whole graph connected. Therefore, e=(u,v)
is a necessary condition for cutting edges and e
is a tree edge.

Let v
be a child node of u
. If the whole graph is not connected after cutting off e
, then it must be that T(v) and parts other than
T(v) are not connected. This shows that all nodes inside
T(v) must cross e to reach outside T(v) , that is, e is a bridge communicating inside and outside T(v) .




Consider how to quickly judge this situation. According to the experience of solving the cut point, it is not difficult to find that e
is the cut edge, which is equivalent to gv>du
, that is, low[v] > dfn[u]. Compared with the cut point judgment rule, the reason why there is no equal sign is that the edge is deleted at this time instead of the node, so as long as the subtree can bypass e to
reach
the part other than T(v), including u
itself, then e
is not cutting edge. In terms of subtree independence, this means that a subtree can reach u
or its ancestors via a non-tree edge. Then according to the nature of the timestamp (the timestamp of the ancestor is smaller than the timestamp of the descendant), there is this judgment rule.

There is a small detail when solving the cutting edge, which is to judge the ancestral edge.

A simple idea is to record the father when dfs, if the current edge (u, v)
points to the parent of the current node (v=fa(u)
), then skip this edge. There is a problem in this way, that is, an error occurs when there is a double edge, because the heavy edge of the tree edge will also be judged as a tree edge.

The solution is to additionally record the number of the edge. For the vector storage graph, when we push_back the node pointed to by the current edge, we also need to push the number of the current edge into it. For the chained forward star, the trick is to transform in pairs: let cnt=1 initially
, so that the numbers stored in the chained forward star for each side and its opposite side are 2
and 3
, 4
and 5
, and so on.
In this way, the reverse side number can be obtained by XORing the current side number with 1 .

To sum up, when dfs records the current node u
and the number idfe of
the edge fe passed when coming down from fa(u) dfs , then for all outgoing edges e=(u,v) of u , it is only necessary to judge whether ide is equal to idfe ( vector) or idfe⊕1 (chained forward star) can determine whether e is a tree edge, and thus decide whether to ignore the current edge.







The time complexity of the algorithm is O(n+m)
.

4.3.2 Tree difference method

Give another method to solve edge cutting.

According to the independence of subtrees, the
two endpoints (u, v) connected by all non-tree edges
ne must have an ancestor-descendant relationship. This shows that there is a vertical chain between
u and v on the dfs tree T.

Therefore, find
any spanning tree T of the original graph G
, and for
the edges (u, v) not on T
, mark all the edges between u and v
as non-tree edges. It can be realized by tree difference.

The time complexity of the algorithm is O(n+m)
.

4.4 Edge Biconnected Components

Solving for edge biconnected components is very easy.

It is easy to prove that for an undirected connected graph G
, if e
is its cutting edge, then for
any subgraph G′=(E′,V)⊆G of G
, if e∈E′
, then there must be e
as G ’
cut edge.

Delete
all cutting edges of G to get several connected blocks. Since all cutting edges are removed, these connected blocks must be edge biconnected graphs. Therefore, they are the sides of the original image.

After obtaining the double-edge connected components, record the double-edge number of each point, so that it is easy to
shrink the double-edge point of G.

Next, we will introduce the method of using tarjan to realize the contraction point of double-connected components of edges, and the similar method can be applied to the contraction point of point double points.

It is feasible to find all cut edges by tarjan algorithm first, and then find all biconnected components of all edges by dfs, but it is too troublesome. We hope that one pass of dfs can solve the cutting edge + find all the biconnected components of the edge. To do this, we need to make some improvements to the tarjan algorithm.

Specifically, maintain a stack S
, which represents all nodes that have been visited and have not yet formed a complete pair. Every time dfs enters a node, it is first pushed into the stack. This step appears in the shrinkage algorithm of various connected components.

Let the current node be u
, and v
be the child node of u currently traversed
in the dfs tree. If (u, v)
is determined to be a cutting edge, that is, low[v] > dfn[u], then we assert that
all nodes from the top of the stack to v (the points derived from the subgraph, ignored below) form an edge double . Pop these nodes out.

Consider proving the above conclusion.
Let us assume that the connected blocks formed after cutting (u, v) from the original graph are u∈U
and v∈V respectively
. Since it is determined that (u, v)
is a cut edge, it is carried out when leaving node v
and returning to node u , so the node v in the current stack belongs to V all the way up to the top of the stack : the closer to the top of the stack, the later it is visited, and V All the nodes in U∩S are visited after v, and the nodes in U∩S must be visited before v (keep in mind that (u, v) is a cutting edge).







For
all cut edges inside V, we have already disposed of the edge pairs formed by them when dfs reaches them.
Therefore, there must be no cutting edge inside V∩S , and it is exactly a pair of sides. Contradictory method, if V∩S
can be divided into two sides, double V1
and V2
, consider the only cut edge (x∈V1,y∈V2) between V1
and V2 (if the cut edge is not unique, it will contradict the definition of the cut edge) . Since x,y∈T(v) , the cutting edge x,y must be processed before backtracking from v to u . Assume that x on the dfs tree is the ancestor of y . When we leave y and go back to x , we will judge x and y as cutting edges, so that V2 will be popped out of S , which is contradictory to V2⊆S . The conclusion is proven.













The whole algorithm can be regarded as a process of continuously disconnecting a "remote" cutting edge from the original graph and peeling off a layer of connected components. The qualitative description of "remote" is that there is no cut edge in the peeled connected component (the cut edge that has been disconnected is not counted), then this connected component is naturally a pair of sides. Corresponding to the tree formed after shrinking the points, it is to peel off a leaf node each time through a cut edge (each node is a pair of sides).

The above ideas will also be applied when pointing double contraction points and SCC contraction points, readers need to understand carefully.

The time complexity of the algorithm is excellent O(n+m)
. See Example III for the code.

4.5 Point Biconnected Components

See Chapter 3 of Advanced Graph Theory for round-square trees, and the bicorrelation property of points is also introduced in this part.

4.6 Examples

I. P3469 [POI2008] BLO-Blockade

A good practice question for tarjan to find cut points.


Since the topic is asking for ordered pairs, it is advisable to set the sizes of connected blocks formed after blocking node u to be s1, s2, ⋯, sk respectively
. It is not difficult to obtain the answer as ∑si(n−si)
.

Don't forget that u
itself forms a
connected block with a size of 1, and after removing all the connected blocks formed by the
node v that determines that u is a cut point, there is a connected block with a size of sk=n−1−∑i=1k−1si .

Time complexity O(n)

II. SP15577 STC10 - Blockade

Double experience questions.

III. P2860 [USACO06JAN] Redundant Paths G

The title is equivalent to finding the least number of edges to add to make the entire graph a double edge, that is, there is no cut edge.

Considering the edge double contraction point, all the edges on the obtained tree T
are cut edges on the original graph. According to the conclusion of edge cutting, if you
add an edge between (u, v), let U be the corresponding node on the tree where the edge of
u is double after the contraction point, V is the same, then it is equivalent to adding U, V All the edges on the simple path between become non-cut edges on the original graph.



Therefore, we want to cover every edge of T with the least number of paths . There is a classic conclusion (or direct perceptual understanding) about this, and the answer is that
the number of leaves of T is divided by 2
and rounded up.

It is very easy to prove that this is the lower bound of the answer, since each chain annihilates at most two edges from its leaves to its only neighbor. Discuss specifically when there are only two nodes, which is trivial. Next, a construction method to achieve this lower bound is given.

Saying that two nodes match means that in the final solution, there exists a link connecting them.

First of all, when the number of leaves is odd,
matching a leaf with a node with degree ≥ 3 can be transformed into the case where the number of leaves is even. If there is no
node with degree ≥ 3, then T
is a chain, which contradicts that the number of leaves is odd.

Consider pairing all the leaves in any pair first, and then adjust.
If there is an edge (u, v) that is not covered in the current scheme , check the connected blocks U, V where u and v are respectively located
after breaking (u, v) .

It is impossible for U
or V
to have only one leaf (the leaf here is relative to the original tree, that is, the
leaf on the original tree T, not
the leaf of U itself), because if not, the only leaf and another leaf It must go through (u, v) when matching
, which is inconsistent with (u, v)
not being covered.

In the same way, it can be proved that U
or V
cannot have an odd number of leaves.

According to the above conclusions, the current scheme must be that
all even-numbered leaves of U are pairwise matched, and
all even-numbered leaves of V are pairwise matched.

Assume
that two paired leaves of U are u1, u2 , and their LCA when
u is the root is ud . Similarly for V , define v1, v2 and vd .




The current scheme is that all edges on u1→ud→u2 and
v1→vd→v2
are covered, but through adjustment, u1
and v1
, u2
and v2
match, then ui→ud→u→v→vd→vi
All edges are covered. The originally covered edge is still covered, and (u, v)
is also covered.

Therefore, for the current solution, if a certain edge is not covered, the above adjustment will definitely make the original covered edge still be covered, and this edge will also be covered, while not changing the original number of #leaf2 chains
. The upper bound of the answer is proven.

Time complexity O(n+m)
.

#include <bits/stdc++.h>
using namespace std;
const int N = 5e3 + 5;
int n, m, dn, deg[N], dfn[N], low[N];
int cn, col[N], stc[N], top;
vector<pair<int, int>> e[N];
void form(int id) {
    
    
  cn++;
  for(int x = 0; x != id; ) col[x = stc[top--]] = cn;
}
void tarjan(int id, int eid) {
    
    
  stc[++top] = id, dfn[id] = low[id] = ++dn;
  for(auto _ : e[id]) {
    
    
    if(_.second == eid) continue;
    int it = _.first;
    if(!dfn[it]) {
    
    
      tarjan(it, _.second);
      low[id] = min(low[id], low[it]);
      if(low[it] > dfn[id]) form(it);
    }
    else low[id] = min(low[id], dfn[it]);
  }
  if(!eid) form(id);
}
int main() {
    
    
  cin >> n >> m;
  for(int i = 1; i <= m; i++) {
    
    
    int u, v;
    cin >> u >> v;
    e[u].push_back(make_pair(v, i));
    e[v].push_back(make_pair(u, i));
  }
  tarjan(1, 0);
  if(cn == 1) puts("0"), exit(0); // 这句判断其实不要也可以
  for(int i = 1; i <= n; i++)
    for(auto _ : e[i]) {
    
    
      int it = _.first;
      if(i < it && col[i] != col[it]) deg[col[i]]++, deg[col[it]]++;
    }
  int leaf = 0;
  for(int i = 1; i <= cn; i++) leaf += deg[i] == 1;
  cout << (leaf + 1 >> 1) << endl;
  return cerr << "Time: " << clock() << endl, 0;
}

IV. CF51F Caterpillar

The title requires that no rings exist, so we naturally think of shrinking all sides into one point. After shrinking, the whole graph will become a forest. First process each tree, and then use the number of connected blocks-1
operation to connect them.

Consider how to turn a tree into a caterpillar with the fewest operations after determining the main chain.

For nodes other than the main chain, consider whether it is a leaf that is finally hung next to the main chain. Considering the main chain as the root, point pairs with ancestor-descendant relationship cannot be selected as leaves at the same time, because there is an ancestor between the descendant and the main chain at this time, indicating that the distance from it to the main chain is ≥ 2, which is inconsistent with the meaning of the question
.

Therefore, it is equivalent to selecting the most nodes so that there is no ancestor-descendant relationship between these nodes. Our decision is to select all leaves, because if a non-leaf is selected, we must be able to deselect it and select all its children, which must be better. This conclusion can be reached by constant adjustment.

Therefore, the final reserved nodes are all the nodes on the main chain and the nodes we selected as leaves. This means that for a certain path P
, the minimum number of operations corresponding to it as the main chain is n−|P|−L
, where n
is the size of the tree, and L
is the number of leaf nodes outside the main chain.

It is easy to find that when
both ends of P are not leaves, it can always be adjusted so that
both ends of P are leaves and n−|P|−L
remains unchanged or becomes smaller: extend to any direction that can be extended, and each time |P|
increases 1
, but L
is either unchanged (when the extended point is a non-leaf), or only decreased by 1
(when the extended point is a leaf).

Therefore, if the number of leaves in the original image is K
, the number of operations is n−K+2−|P|
. n−K+2
is a fixed value. We want |P|
to be the largest. Naturally, the diameter of the tree is selected, and at the same time, it just meets
the requirement that both ends of P are leaves.

Time complexity O(n+m)
. code.

5. Directed graph connectivity

5.1 Strongly Connected Components

The full name of Strong Connected Component is Strong Connected Component, abbreviated as SCC. Here are some definitions and basic properties:

In the directed graph G
, if two points u, v (u≠v)
can reach each other, the two points are said to be strongly connected, and there is strong connectivity between them.
In a directed graph G
, if any two nodes are strongly connected, then G is said
to be a strongly connected graph. A maximally strongly connected subgraph of
a directed graph G is called a strongly connected component of G. Obviously, strong connectivity is transitive. Strongly connected components are useful when solving problems related to connectivity, because all points in the same strongly connected component are equivalent when only connectivity is concerned.



5.2 Tarjan algorithm for SCC contraction point

With the precedents of using the tarjan algorithm to solve cut points and cut edges, point double and edge double shrinkage points, we can naturally adjust these methods to solve the shrinkage point problem of strongly connected components.

5.2.1 Properties of directed graph dfs tree

We examine the shape of the directed graph dfs tree Td
, and thus obtain the criterion for judging SCC.

In addition to tree edges, Td
also has forward edges, atavistic edges, and cross-fork edges.
The forward edge and the ancestral edge are obtained by the two orientations of the ancestral edge of the dfs tree Tu in the undirected graph , and the cross-fork edge is
the edge between two subtrees of a certain node in Td. Tu
has no cross edges because
the subtrees of Tu are independent.

Why does Td
have a horizontal fork? Because a later visited SCC can connect to the previous visited SCC. For example, G=({1,2,3},{1→2,1→3,3→2})
, if we visit node 2 first in dfs
, then when visiting node 3,
we will find from 3
to 2
fork side.

Next, when discussing the directed edge u→v
, let d=lca(u,v) , the first node of
d→u is u′ , and v′ is the same. Let fai denote the father of i on Td .





Although the subtrees are less independent, we can still discover some properties:

For the forward edge u→v
, u
itself can reach v through the tree edge
, and there will be no effect after deletion. It doesn't even affect connectivity.
For the atavistic edge u→v , it will make all points on the path from v to u on
Td form SCC. The combination of multiple atavistic edges can form larger and more complex SCCs. For the cross-edge u→v , the timestamp of u must be greater than the timestamp of v. Otherwise, since u→v is a horizontal fork, d≠u and d≠v . Because u→v , v can be accessed when visiting T(u′) , so v∈T(u′) , so d=u′ , a contradiction. Combining the above three points, it can be seen that both the atavistic edge and the cross-fork edge make the time stamp decrease, and only the tree edge makes the time stamp increase. Forward edges do not affect strong connectivity, so all forward edges are ignored.















In order to explore the impact of the cross-edge on the strong connectivity, consider the cross-edge u→v
, then dfnv<dfnu
.
Therefore, for a point pair (u,v) where dfnv<dfnu
, we want to know the necessary and sufficient conditions for v
to reach u .

If dfnv<dfnu
, then v
can reach u
if and only if v
can reach d
.

Sufficiency: Obviously.

Necessity: Considering that a certain step x→y on the path
satisfies dfnx<dfnu≤dfny
, obviously this step exists. Since dfnx<dfny
, x→y
is a tree edge. When y=u
, obviously u∈T(x)
; otherwise y≠u
, then u is visited after
x and before
y , combining x→y is the process of tree edge and dfs, u∈T(x) . Thus if dfnv<dfnu and v is reachable to u , then v is reachable to fau . Apply this conclusion to all nodes of the path u→u′ in the tree , then v can reach d .










Therefore, for a transverse edge u→v
, it affects the strong connectivity if and only if v
reaches d
.


According to the above conclusions, the low array of the directed graph tarjan algorithm should be defined as the atavistic edge u→v of all nodes u in the subtree
, and the minimum timestamp of all v of the transverse edge u→v of v
reaching d . There are and only these edges affect strong connectivity.


5.2.2 Algorithm flow

If u and v
are the shallowest nodes of the SCC at the same time, it is easy to prove that d
belongs to the SCC, which is a contradiction. Therefore each SCC
has only one shallowest node on Td. We want to count the corresponding SCC at each shallowest node. Consider the qualitative description of the "formation of an SCC" situation.

For node u
, if it is not the shallowest node of a certain SCC, according to the definition of SCC, it must be able to reach the shallower ancestor with smaller time stamp after going through several transverse fork edges and ancestry edges. Conversely, if it is, then its entire subtree cannot jump out of x
to a shallower ancestor. According to this, we get
the necessary and sufficient condition for judging that u is the shallowest node of a certain SCC: low[u] >= dfn[u], and its equivalent expression is dfn[u] == low[u].

Similar to edge double contraction points, we maintain a stack S at all times
, indicating nodes that have been visited but have not yet been determined to form an SCC. Every time the shallowest node u is found
, all the nodes from the top of the stack to u
are popped out (since u
is the first node visited by the SCC, so it has the deepest position in the stack), indicating that they form an SCC .

The correctness of the algorithm depends on the strong connectivity of all pop-up nodes and the maximality of the corresponding SCC. The proof method is similar to the correctness proof of the side double contraction point, here is a brief explanation.

Strong connectivity: Let the pop-up point set be V
, if
the point derived subgraph of V contains two SCC G1
and G2
, set the corresponding point set as V1
, V2
, and
the shallowest node of V1 is u , and the shallowest node of
V2
is v
, then when going back to v in the process of dfs
, since v is determined to be the shallowest node of
G2 , and V2 is accessed after V1 , the stack is continuously popped until v is popped , and the popped point set V ' must contain V2 . Contradicts with V2⊆V .






Maximality: If there is a strong connection between v
and u
but v∉V
, according to
the shallowest property of u, v
must be popped before that. Considering the shallowest node v' when popping up
, then dfn[v'] == low[v'], that is,
there is no edge in the subtree of v' that can reach u
that affects the strong connectivity, so u, v '
not belong to the same SCC. According to the transitivity of strong connectivity, u and v
are not strongly connected, which is a contradiction.

Finally, consider how to find low. For the tree edge u→v
, naturally use low[v] to update low[u], the key is to judge the type of other edges.

For the forward edge u→v
, updating low[u] with dfn[v] has no effect because dfn[v] <= low[u].
For atavistic edge u→v
, update low[u] with dfn[v].
For the cross edge u→v
, if v
cannot reach d
, then v must have been popped when backtracking
from v′
to d , otherwise it must not have been popped, that is, v reaching d is equivalent to v being currently popped from the stack. No proof of correctness, perceptual understanding: if v is not reachable to d , then v and d are not strongly connected, so if v is not popped up when v′ goes back to d , then v and d will be popped together ( when backtracking from x Only the points within T(x) will be popped up ), which is contradictory; similarly, if v can reach d , then v and d are strongly connected. At this time, if v is popped up, since d is not popped up, v and d are not strongly connected , contradiction (the reason for calling it perceptual understanding is that there is a circular argument between the correctness of low and the correctness of the pop-up strongly connected component, and more details need to be discussed to be rigorously summarized). Therefore, if v is still on the stack, update low[u] with dfn[v]. Since the atavistic edge u→v






















Make u and v
strongly connected, so v
must not be popped at this time, that is, v
is in the stack.

In summary, the following method can be obtained: for tree edge u→v
, update low[u] with low[v]; for non-tree edge u→v
, if v
is in the stack, update low[u] with dfn[v] ].

5.2.3 P3387【Template】Short point

Because you can pass the same point multiple times, once you enter a certain SCC, you can definitely go through all the points in it and get the contribution of the sum of the weights of all points in it. But once you leave, you can't come back.

Therefore, the DAG is obtained by shrinking all the SCCs, and the weight of each SCC is equal to the sum of the weights of all the points it contains. The problem is to find the longest path so that the weight of all SCCs on the path is and max. Topological sorting DP is sufficient, and the time complexity is O(n+m)
.

From the above, we can find that SCC contraction is often combined with topological sorting, because the result after contraction is a directed acyclic graph.

Both E-BCC and V-BCC can get a tree after shrinking points, and the latter is a round square tree after processing.

#include <bits/stdc++.h>
using namespace std;
const int N = 1e4 + 5;
int n, m, cn, col[N];
int a[N], val[N], f[N], deg[N];
int top, stc[N], vis[N], dn, dfn[N], low[N];
vector<int> e[N], g[N];
void tarjan(int id) {
    
    
  vis[id] = 1, dfn[id] = low[id] = ++dn, stc[++top] = id;
  for(int it : e[id]) {
    
    
    if(!dfn[it]) tarjan(it), low[id] = min(low[id], low[it]);
    else if(vis[it]) low[id] = min(low[id], dfn[it]);
  }
  if(dfn[id] == low[id]) {
    
    
    col[id] = ++cn;
    while(stc[top] != id) col[stc[top]] = cn, vis[stc[top--]] = 0;
    vis[id] = 0, top--;
  }
}
int main() {
    
    
  cin >> n >> m;
  for(int i = 1; i <= n; i++) scanf("%d", &a[i]);
  for(int i = 1; i <= m; i++) {
    
    
    int u, v;
    scanf("%d%d", &u, &v);
    e[u].push_back(v);
  }
  for(int i = 1; i <= n; i++) if(!dfn[i]) tarjan(i);
  for(int i = 1; i <= n; i++) {
    
    
    val[col[i]] += a[i];
    for(int it : e[i])
      if(col[i] != col[it]) {
    
    
        g[col[i]].push_back(col[it]);
        deg[col[it]]++;
      }
  }
  queue<int> q;
  for(int i = 1; i <= cn; i++) if(!deg[i]) q.push(i);
  while(!q.empty()) {
    
    
    int t = q.front();
    q.pop(), f[t] += val[t];
    for(int it : g[t]) {
    
    
      f[it] = max(f[it], f[t]);
      if(!--deg[it]) q.push(it);
    }
  }
  int ans = 0;
  for(int i = 1; i <= cn; i++) ans = max(ans, f[i]);
  cout << ans << endl;
  return 0;
}

5.3 Examples

I. AT3945 [ARC092D] Two Faced Edges

For strong connectivity correlation, the DAG is first considered by shrinking points.

For the edge connecting SCC (S1, S2)
, the number of SCC is reduced after the reverse if and only if S1
can reach S2 without going through this edge on the DAG
.
The number of paths between any two points can be calculated in O(nm),
and the min
judgment is taken for 2. Or directly calculate the modulus of the number of paths, and the probability of error is small.

But the edge inside the SCC is not easy to handle. If u → v is reversed
, we assert that connectivity does not change if u
can still reach v .

First of all, for all point pairs (x, y) inside the SCC
, from x
to y
either must pass through
the edge u→v, or it is not necessary. For the latter, the reverse u→v
does not affect
the connectivity of x,y. For the former, x can still reach y if u
can still reach v , otherwise the opposite edge v→u will have no effect. Because it must go through u→v , x has no other path to reach v . After the reverse direction, x and v are not connected, and v→u is useless.








In summary, we have obtained
the necessary and sufficient condition for judging the strong connectivity of the internal edge u→v in SCC after the reverse direction: u can still reach v
after removing u→v . This is equivalent to that for each outgoing edge u→v1, v2,⋯, vi of a point, it is required to find out which points u can reach without passing through u→vj .




Consider this is a form of prefix v1∼vj−1
and suffix vj+1∼vi
, so scan both the front and back, record the accessibility of each point when scanning each outgoing edge, and scan the current outgoing edge When u→v,
if v
is already reachable,
mark u→v as still reachable after being removed. Since each point in SCC will only be traversed once when adding all outgoing edges in sequence, the total time complexity is O(nm)
.

Note that what we consider is the reachability of each point starting from u
while retaining a prefix or suffix edge starting from u , so when dfs to u again , we need to return in time, otherwise we will traverse to the point starting from u that does not belong to the current Prefix or suffix edge. Furthermore, we find that for the edge u→v connecting SCCs , we also want to judge whether u can reach v after removing this edge . This is consistent with what needs to be solved for the edges inside the SCC, so all edges can be considered equivalently. It's just that for the edges between different SCCs, if u⇝̸v , reversing u→v will not change the number of SCCs, and vice versa. This is exactly the opposite of the edge inside the SCC. This eliminates the need to explicitly create a DAG.








Performing an O(nm)
deep search on the entire graph will cause T to fly away, and we need a more efficient algorithm. Consider finding
the first unvisited point among all outgoing edges of u each time, which can be realized by using _Find_first() of bitset.

Specifically, let vis represent whether each node is visited, and e[u] represent
all exit points of u, then (~vis & e[u])._Find_first() is what you want. hour

Between complexity O(n3w)

Enlightenment: The information of removing one position from the sequence can be obtained by combining the prefix and suffix.

II. P3436 [POI2006] PRO-Professor Shu

First of all, it is easy to find that if an SCC or self-loop with a size greater than 1
(hereinafter referred to as an illegal structure) can reach the teaching building, then the number of paths from each point in the illegal structure to the teaching building is infinite. Therefore, SCC shrinks points + constructs reverse graph topology sorting, and illegal structures cannot be enqueued. Topological sorting records the path number fi at the same time,
indicating the number of paths from i
to n+1 .
Because the modulo cannot be taken, it is necessary to
take min for 36501
.


But the question does not guarantee that every point can reach the teaching building (the title is wrong), so it is necessary to first enter the non-teaching building point with an in-degree of 0 on the reverse graph into the team and run the topological sort. Note that illegal structures can be enqueued at this time, because they have no path to the teaching building.

Finally, if there is a point that is not enqueued, it means that this point can reach an illegal structure, so the number of paths is also infinite. In addition, if fi>36500
does not meet the meaning of the question. The time complexity is linear.

If the SCC where n+1
is located is an illegal structure, it cannot be enqueued.
Using vector to save the image will be MLE, and the space limit of the original question is 64MB.
code.

*III. P7737 [NOI2021] Celebration
For an SCC, shrinking it to one point does not affect the answer. The nature given by the topic shows that the connectivity of the graph can be described by a tree. Specifically, topological sorting retains the last incoming edge of each point. Get an outgoing tree.

For given 2(k+1)
city endpoints, if i
is the ancestor of j
, and s
can reach i
, and j
can reach t , ​​it means that all cities on the chain
i→j may pass through, and the tree section can be calculated
Chain and that's it.

Time complexity O(nlognloglogn)
. loglogn
is the complexity of sorting.

IV. CF555E Case of Computer Network

For an edge pair, we can always arrange an orientation for its internal edges so that any point on it can reach all other points. That is, both sides must be oriented as SCC.

Proof: first give the lemma, for a strongly connected point set S
, there is a direction path P=u→p1→⋯→v
, if u, v∈S , after adding
all pi into the S set, S is still Strong connectivity. This is easy to prove.


According to the lemma, for a pair of sides G=(V,E)
, we first find any ring P among them
, and orient it into a directed ring. Let the initial strongly connected set be
the point set of P. Next, continuously select
a chain C whose both ends belong to S and whose edges are not directed , orient
it into a directed chain and add all points on the chain to S.

C
must exist. Consider an edge (u,v)
such that u∈S
and v∉S
.
Such an edge must exist when S≠V , otherwise G
is disconnected. Starting from u
and walking to v
, it is inevitable to return to S in the end
. Because the side of G is double-connected, if the side
(u, v) is removed , v must be able to return to u , and naturally it must be able to return to S. The path already traveled when returning to S for the first time is a legal C.





Since the size of G
is limited, the above process must eventually end, and at this time S=V
, that is, V
is strongly connected. Orient the edges that have not been oriented arbitrarily, and the conclusion is proved.

Therefore, we first obtain a tree by shrinking the points of the original graph. If s and t
are not connected, there is no solution. Otherwise,
the double G(s) at the point of s
must reach
the double G(t) at the point of t
, so G The orientation of all edges on the simple path from (s)
to G(t) has been determined.
If there is a directional contradiction of an edge, there is no solution, and a chain can be marked through LCA + difference on the tree. Open two difference arrays to record whether the edge connecting the current point to its parent is designated as up or down. If there are values ​​at the same time, there is no solution.

The time complexity is O(m+(n+q)logn)
, and the bottleneck lies in finding LCA. Linearity can be achieved by using four hairs. code.

6. Euler diagram

Euler, God forever!

6.1 Definition and Judgment

Euler path: A path that passes through all edges in a connected graph exactly once is called an Euler path.
Euler circuit: A circuit that connects all edges in a graph exactly once is called an Euler circuit. A loop, that is, a path that starts and ends at the same point.
Euler Graph: A directed or undirected graph with an Euler circuit is called an Euler graph.
Semi-Eulerian Graph: A directed or undirected graph with Euler paths but no Euler circuits is called a Semi-Eulerian graph.
The above definition (fog) is basically not used when doing the questions.

Strictly speaking, a Euler graph can draw a complete graph from any point as a starting point and then return to that point, while a semi-Euler graph can only draw a complete
graph from two points S, T, where S, T
as the start and end points, respectively.

Judgment of Euler graph: An undirected graph G
is an Euler graph if and only if G
is a connected graph and the degree of each vertex is even. A directed graph G
is an Eulerian graph if and only if G
is an SCC and the in-degree and out-degree of each vertex are equal.

Consider proving the above conclusion.

Whether it is for undirected graphs or directed graphs, the necessity is obvious. Considering the shape of the final Euler circuit, every time you enter a point, you have to go out from that point, so the outgoing edge and incoming edge must be offset by two. For the starting point, the edge going out at the beginning and the edge going back to it at the end are also offset, so the existence of an Euler circuit in a directed graph must satisfy that the out-degree and in-degree of each point are equal. Similarly, it can be proved that the degree of each point in an undirected graph must be an even number.

Sufficiency is proved by the method of construction. Considering an undirected graph, first find any cycle P on the graph
(it does not need to be an Euler circuit). Since all isolated points are removed, the degree of each point is ≥ 2
, so the loop must exist. Then delete all edges of P from the graph
, and delete all isolated points. All subgraphs formed are still such that the degree of each point is even, because
the degree of each point in P is 2
. Since each subgraph
has an intersection point with P, it is only necessary to connect the Euler circuit of the subgraph
to P to obtain the Euler circuit of the original graph. So we do the same for subgraphs. The number of edges is finite, so the whole process must end, and then the Euler circuit of the original graph is obtained. In the same way, the sufficiency of the judgment condition of the directed graph Euler circuit can be proved.

Judgment of a semi-Eulerian graph: An undirected graph G
is a semi-Eulerian graph if and only if G
has two vertices of odd degrees. A directed graph G
is a semi-Eulerian graph, if and only if G is
weakly connected, there exists exactly one vertex such that out-degree minus in-degree equals 1
, there exists exactly one vertex such that in-degree minus out-degree equals 1
, and all remaining vertices In and out are equal. Weak connectivity is defined as the connection of the entire graph after replacing all directed edges with undirected edges.

6.2 Finding Euler's Path: Hierholzer's Algorithm

The core of the Hierholzer algorithm is to continuously insert a loop into a certain point of the current loop, which is exactly the same as, or completely equivalent to, the proof of the sufficiency of the judgment condition for the existence of the Euler loop.

Consider the directed graph first, because the directed graph does not need to consider the problem of multiple edges.

6.2.1 Naive methods

According to the process, we have a simple implementation method: first, dfs finds any ring P passing through a certain point
(does not need to be a simple ring), and
marks all points on P as deleted. Then join
each node p1,p2,⋯,p|P|,p1 on P in turn
. Before adding pi
, we recursively find
the Euler circuit of the subgraph where pi is located (some edges are deleted and split into several subgraphs), and then insert the current path. So this is a recursive form of the algorithm.

Every time a point is enumerated, all its outgoing edges must be traversed to find the first edge that has not been deleted, and the complexity is O(m2)
.

If a doubly linked list is used to maintain all the remaining outgoing edges of each point, each edge will only be traversed once, and the time complexity is O(n+m)
.

Furthermore, we found that the ring edges deleted each time must be the first few of all the outgoing edges of each node that have not been deleted. That is to say, if a traversal order (u,v1),⋯,(u,vout(u)) is specified for
all outbound edges (u,vi) of u , then the first few must be deleted when finding the ring. Edges (u,v1),(u,v2),⋯,(u,vk) . Because we will not regret the operation of taking a certain edge because we cannot find the ring.


Keep searching deeply without thinking, and you will definitely find the ring in the end.

prove this conclusion. Let's start from u
to find the ring, and delete the first outgoing edge of the current node that has not been deleted each time. When we go to node v≠u
, assuming that this is the i-th
time to enter v
, then we will only leave v
for a total of i−1
times (each departure must correspond to one entry, and before the i-
time entry, there are only i−1
times Enter).
Therefore, only i−1
outbound edges of v are deleted at this time , and v
has no less than i
outbound edges:
entering v for the ith time
means in(v)≥i
, and in(v)=out(v)
So out(v)≥i
. This shows that we must be able to
go out from v to other nodes.

Therefore, in the end, it is only possible
to go to other nodes at u. But this means that a ring has been found at this point.

According to the above conclusions, we don't need to maintain a doubly linked list. The chained forward star used for image storage can also meet the requirements, because only the beginning edge will be deleted each time. After this improvement, the head of the linked list is very similar to the current arc of the network maximum flow Dinic algorithm, both of which record the first useful edge to save the time of jumping useless edges one by one.

This conclusion also proves that the complexity of finding a ring is linear with respect to the number of edges on the ring, so the total complexity is O(n+m)
.

Note that it is necessary to use a doubly linked list to maintain the process of inserting a ring into the current loop, otherwise the complexity will degenerate to O(n(n+m)) (
if once you reach the target node other than the target node, you will find it when you go out ring, the complexity will degenerate to O(m(n+m)))
. Because the complexity of processing a ring in this way becomes the sum of the numbers of all unprocessed edges.

6.2.2 The clever way

The time complexity of the above approach is good enough, but it is a little complicated to implement. We wish the algorithm could be simpler.

We can use our own language to describe what the complex method does, and then think about where it can be simplified.

Looking at it as a whole, we have achieved nothing more than the following steps: find a ring from a starting point, and then start to find a ring from each starting point on the ring... and continue to recurse.

Then think about where the trouble is. We will find that in order to start looking for a ring from each starting point on the ring in turn, we need to find and discharge the ring explicitly, and then process all the nodes above in sequence. So we need a dfs function to find the ring, and another recursive function to solve the Euler circuit problem.

This is too stupid, because no matter what order the nodes on the ring are arranged to find the ring, it will not affect the correctness of the Euler circuit. We just find the ring and insert it, and changing the order will not make the problem unsolvable.

Therefore, it is considered to directly search for each node on the ring during the backtracking process of dfs. In other words, reverse the original order of finding the ring, so that there is no need to explicitly find the current ring first, but in the process of backtracking, insert the current ring into the loop while looking for the current point.

To sum up, we have obtained the specific steps of the most commonly used algorithm for solving Euler circuits - the Hierholzer algorithm: traverse
all outgoing edges (u, v) of the current node u
, if (u, v)
has not been traversed, then go to the node v
deep search. After traversing all outgoing edges, add u
to the path. What you end up with is a reverse Euler path. Just turn it upside down.

If the smallest lexicographic order is required, it is only necessary to sort all outgoing edges of each point from small to large at the beginning. In this way, looking from left to right on the Euler circuit, the successor of each point has taken the theoretical minimum value.

6.2.3 Undirected graph and Eulerian path
Above, we propose and optimize the solution method of directed graph Euler path in two sections.

For the Euler circuit of an undirected graph, it can be done similarly to the Euler circuit of a directed graph. The only point to note is that it needs to judge the weight of the edge. Use the pairwise transformation technique when finding the bridge edge, use 2k
and 2k+1
to store the two directions of an edge, and open the bucket to record. You can't just sentence the ancestral side, because there may be multiple sides.

For undirected graphs and eulerian paths for directed graphs, note that dfs must start at a singularity or the only point where the out-degree is greater than the in-degree. There is no difference between the other places and the Euler circuit.

Template question P7771 [Template] The Euler path code is as follows.

#include <bits/stdc++.h>
using namespace std;
const int N = 2e5 + 5;
int n, m, lar, top, stc[N], in[N], hd[N];
vector<int> e[N];
void dfs(int id) {
    
    
  for(int &i = hd[id]; i < e[id].size(); ) dfs(e[id][i++]);
  stc[++top] = id;
}
int main() {
    
    
  cin >> n >> m;
  for(int i = 1; i <= m; i++) {
    
    
    int u, v;
    scanf("%d%d", &u, &v);
    e[u].push_back(v), in[v]++;
  }
  for(int i = 1; i <= n; i++) {
    
    
    sort(e[i].begin(), e[i].end());
    if(abs((int) e[i].size() - in[i]) > 1) puts("No"), exit(0);
    if(e[i].size() > in[i])
      if(lar) puts("No"), exit(0);
      else lar = i;
  }
  dfs(lar ? lar : 1);
  if(top != m + 1) puts("No");
  else {
    
    
    reverse(stc + 1, stc + top + 1);
    for(int i = 1; i <= top; i++) cout << stc[i] << " ";
  }
  return 0;
}

6.3. Examples

I. P2731 [USACO3.3] Riding the Fences

Undirected graph minimum lexicographic Euler path board problem. Note that there are heavy edges, so only the number of the edge can be recorded instead of the two vertices to judge the weight.

II. P1127 Word chain

From the first character of each string to the last character, just run a directed graph Euler circuit. Note that the sorting of the adjacency linked list should be sorted according to the lexicographical order of the strings stored in each edge, not the number of nodes.

III. P1341 Unordered letter pair

board title.

IV. P3443 [POI2006] LIS-The Postman

The restriction of each path segment is that the two adjacent edges appearing in the segment must go successively, because a directed edge appears only once.

All restrictions form a chain of one-way relationship, similar to the number on the CSP2019 T4 tree, shrink this chain into an edge from the start point to the end point, and run the Euler circuit. Finally, when outputting this edge, it needs to be expanded into a chain, so the sequence of nodes on each chain should be recorded.

If there is a cycle or bifurcation in the restriction relationship, there is no solution, which can be maintained by union search or linked list. Time complexity linear logarithmic.

There are still a lot of details, code.

V. P3520 [POI2011] SMI-Garbage

Let f(i) denote the number of edges
with i as one end that need to pass through.
For a circuit, the degrees of all points are even, so
the parity of f(i) does not change after one operation. Therefore, if there exists i
such that f(i)
is odd, there is no solution. Otherwise, notice that there is a necessary and sufficient condition for each connected block of the graph formed by the edges that need to pass through to have an Euler circuit, and run the Euler circuit on this graph. Since it is required not to pass through the same point, and there must be a loop between the same points on the path, the loop between the same points is popped up by means of the stack. Time complexity O(n+m)
.

The edges that do not need to be passed can be ignored directly, because whether there are solutions has nothing to do with these edges: if f is
even, we must be able to construct an edge that does not need to be modified, otherwise there is no solution.

VI. P3511 [POI2010] MOS-Bridges have no solution
if 2∤degi exists
.

Dichotomous answer, if there is a side that cannot go in both directions, then the current answer has no solution, otherwise the direction of some sides has been determined, and the remaining sides have two directions to choose from.

Considering the necessary and sufficient condition for the existence of an Euler circuit in a directed graph, the out-degree and in-degree of all points are equal, and the final out-degree of each point can be calculated accordingly. Note that if (u, v)
is oriented as u→v , the out-degree of
u increases by 1, otherwise the out-degree of v increases by 1 , which naturally gives us a network flow model: each edge is abstracted into a point, S→e capacity 1 , if l≤mid , then e→u capacity 1 , if p≤mid, then e→v capacity 1 , i→T capacity degi2 , use the maximum flow to check whether there is a solution that orients all edges and satisfies the constraints. If it exists, the current answer has a solution, otherwise there is no solution.













After finding the final answer, restore the directed graph according to the orientation scheme of the edges, and just run the Euler circuit. Time complexity O(mm−−√logV)

epilogue

Congratulations, the elementary graph theory is all completed! Looking forward to further development.

Guess you like

Origin blog.csdn.net/aliyonghang/article/details/130897372