题解/算法 {352. 闇の連鎖}
@LINK: https://www.acwing.com/problem/content/description/354/
;
A graph with N N N points and ( N − 1 ) + M (N-1) + M (N−1)+M undirected-edges which consists of two types: Type- A A A contains N − 1 N-1 N−1 edges that forms a tree with these N N N points, and Type- B B B contains M M M edges. (therefore, this graph must be a connected-graph due to a tree which is inner in the graph)
One solution is a choice consists of one edge from Type-A and one edge from Type-B, let it denotes ( a , b ) (a, b) (a,b) such that when we remove these two edge a , b a,b a,b, this connected graph no longer being connected (that is, there exists a pair of points ( a , b ) (a,b) (a,b) such that two points can not arrive to each other using whichever Type-A or Type-B edges).
For example, we have
N
=
5
N=5
N=5 points, Type-A edges are
(
0
−
1
)
(
1
−
2
)
(
2
−
3
)
(
3
−
4
)
(0-1) (1-2) (2-3) (3-4)
(0−1)(1−2)(2−3)(3−4), Type-B edges are
(
0
−
4
)
,
(
2
−
4
)
(0-4), (2-4)
(0−4),(2−4);
A solution is
(
1
−
2
)
+
(
0
−
4
)
(1-2) + (0-4)
(1−2)+(0−4), finally it becomes two connected sub-graphs
(
0
,
1
)
(
2
,
3
,
4
)
(0,1) (2,3,4)
(0,1)(2,3,4); (the choice
(
1
−
2
)
+
(
2
−
4
)
(1-2) + (2-4)
(1−2)+(2−4) is not a solution)
Cuz we must choose a Type-A edge, suppose it is
(
a
−
b
)
(a-b)
(a−b), if there is no Type-B edge, it would become nonconnected due to all Type-A edges forms a tree, let it denotes
A
,
B
A, B
A,B which are both sub-tree where
a
∈
A
a \in A
a∈A and
b
∈
B
b \in B
b∈B;
But due to the existence of Type-B edge, there may still Type-B edges which is the form
(
x
−
y
)
(x-y)
(x−y) where
x
∈
A
,
y
∈
B
x \in A, y \in B
x∈A,y∈B, as a result the previous disjoint-set
A
,
B
A,B
A,B becomes connects.
Obviously, if no such Type-B edge, you can choose any Type-B edge.
If there is only one such Type-B edge, you can only choose this edge;
If there is more than one such Type-B edges, there is no solution when you choose the Type-A edge
(
a
−
b
)
(a-b)
(a−b);
Pseudocode:
for( edge (a,b) : all Type-A edges){
count = the number of Type-B edges (x,y) such that `x in A` and `y in B`;
if( count == 0){
ans += M;
}
else if( count == 1){
++ ans;
}
}
Now, the crucial thing here (also the vital thing in Graph-Problems) is how to transforming a specific demand (the calculation for count
in here) to a familiar graph-algorithm.
For the tree that consists of all Type-A edges, we use a array
V
[
]
=
0
V[] = 0
V[]=0 where the
x
x
x of
V
[
x
]
V[x]
V[x] denotes a edge on this tree (i.e., a Type-A edge);
For any Type-B edge
(
x
−
y
)
(x-y)
(x−y), let the Type-A edge on the path
x
−
y
x-y
x−y in the tree be
e
1
,
e
2
,
e
3
e1, e2, e3
e1,e2,e3; then performing
V
[
e
i
]
+
=
1
V[ ei] += 1
V[ei]+=1;
Cuz if we choose a Type-A
(
a
,
b
)
(a,b)
(a,b) (the tree divided into two sub-trees denote
A
,
B
A, B
A,B), for all Type-B edges
(
x
,
y
)
(x,y)
(x,y) such that
x
∈
A
,
y
∈
B
x \in A, y \in B
x∈A,y∈B, we will find that the path whose endpoints is
(
x
,
y
)
(x,y)
(x,y) in the tree (consists of all Type-A edges) must contains the Type-A edge
(
a
,
b
)
(a,b)
(a,b);
So, conversely, we get the path on the tree for every Type-B edge, and add with one in the counter for every Type-A edge on that path; (this operation can be done using Modification a path on tree)
Tips:
A edge
(
a
,
b
)
(a,b)
(a,b) is actually identified by a point
x
x
x which is the deeper point of
a
,
b
a,b
a,b (i.e., for a rooted-tree,
x
=
a
x = a
x=a is
d
e
p
t
h
[
a
]
>
d
e
p
t
h
[
b
]
depth[a] > depth[b]
depth[a]>depth[b])
So, the value of a edge
(
a
−
b
)
(a-b)
(a−b) actually corresponds to
V
[
a
]
V[ a]
V[a].
What’s more, for a tree with
N
N
N points
[
0
,
N
)
[0, N)
[0,N) and rooted by
0
0
0; if you want iterate all Type-A edges (i.e., all edges on a tree), getting all edges
(
a
,
b
)
(a,b)
(a,b) and find the deeper point
x
x
x, and that the value of this edge is
V
[
x
]
V[x]
V[x] is not a good device; (cuz you need record
d
e
p
t
h
[
]
depth[]
depth[] for every point)
A better device is, for( x : [1, N))
; there is a property: cuz there are
N
−
1
N-1
N−1 edges, the set of
x
x
x for every edges is
[
1
,
N
)
[1, N)
[1,N); so you just iterate the points which is equivalent to iterating all edges.
int n, m;
scanf("%d%d", &n, &m);
Graph_UnWeighted G( n, n * 2);
G.Initialize( n);
for( int i = 1; i < n; ++i){
int a, b;
scanf("%d%d", &a, &b);
-- a, -- b;
G.Add_edge( a, b);
G.Add_edge( b, a);
}
DifferentialOnTree_WeightedEdge< int> Diff( &G);
Diff.Initialize( 0);
LCA< 17> lca( &G);
lca.Initialize( 0);
for( int i = 0; i < m; ++i){
int a, b;
scanf("%d%d", &a, &b);
-- a, -- b;
Diff.Add_interval( a, b, 1, lca.Get_lca( a, b));
}
Diff.Restore();
int ans = 0;
for( int i = 1; i < n; ++i){
if( Diff.Restored_value[ i] == 0){
ans += m;
}
else if( Diff.Restored_value[ i] == 1){
++ ans;
}
}
cout<< ans;