题解/算法 {352. 闇の連鎖}

题解/算法 {352. 闇の連鎖}

@LINK: https://www.acwing.com/problem/content/description/354/;

A graph with N N N points and ( N − 1 ) + M (N-1) + M (N1)+M undirected-edges which consists of two types: Type- A A A contains N − 1 N-1 N1 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) (01)(12)(23)(34), Type-B edges are ( 0 − 4 ) , ( 2 − 4 ) (0-4), (2-4) (04),(24);
A solution is ( 1 − 2 ) + ( 0 − 4 ) (1-2) + (0-4) (12)+(04), 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) (12)+(24) is not a solution)

Cuz we must choose a Type-A edge, suppose it is ( a − b ) (a-b) (ab), 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 aA and b ∈ B b \in B bB;
But due to the existence of Type-B edge, there may still Type-B edges which is the form ( x − y ) (x-y) (xy) where x ∈ A , y ∈ B x \in A, y \in B xA,yB, 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) (ab);

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) (xy), let the Type-A edge on the path x − y x-y xy 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 xA,yB, 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) (ab) 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 N1 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;
  • 25
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值