Given n vertices and m edges, each vertex has a certain weight. There are q operations, and each operation has three types: 1. query the minimum vertex weights connected to a vertex greater than k. 2. Update the vertex weights of a vertex to k. 3. delete an edge.
Solution: the questions of the 08-year online competition were over five people in the audience, but they were definitely difficult to find and collect questions. From this question, I learned a very effective way to solve the problem of the given operation sequence-reverse processing. I also learned how to set several operations in STL.
We don't want to worry about anything else. We need to consider what the three operations on this issue require us to do. The first operation is to find the minimum point weight of a connected component greater than k, and the second and third operations, if it is a brute-force q * n solution, then it will naturally be simulated.
However, the complexity is too high. q is 0.3 million, n is 20 thousand, and a maximum of 6 billion operations are performed. Because the connected components are involved, we consider using and querying the set. The first operation is to find the minimum weight of a root son that is greater than k. It seems that it is different from what we usually do and check the set. We usually use the root information, this is a highlight of this question. The second operation seems to have to find the root, traverse the son, and update the vertex right. The third operation seems to have to split a set into two sets.
These operations are really scary if they are done in the forward order. The first operation can be handled through the STL set. Isn't the set lower_bound method the topic description function? In the third operation, it is very difficult to split a set. However, if we convert it into a merged set in reverse order, it is much simpler and more elegant without affecting the results. This is Two highlights of this question.
The analysis is almost like this, followed by code implementation. I used the set operation for the first time and read the code of Baidu and a certain cool. The efficiency was good, 256 ms, ranking third.
Test data:
3 3 8
4 5 8
1 2
2 3
1 3
F 1 4
E 1 3
F 2 7
E 2 3
E 1 2
F 2 7
U 3 6
F 3 3
Out: Example XX: 4.500
1 0 1
0
F 1 0
Out: Example XX: 0.00
3 3 8
8 8 8
1 2
2 3
1 3
F 1 9
F 1 8
E 1 3
E 2 3
E 1 2
F 1 8
U 3 6
F 3 7
Out: Example XX: 4.000
3 3 9
8 8 8
1 2
2 3
1 3
F 1 9
F 1 8
U 1 5
E 2 3
E 1 2
E 1 3
F 1 5
U 1 6
F 1 6
Out: Example XX: 4.750
3 3 11
8 8 8
1 2
2 3
1 3
F 1 9
F 1 8
U 1 5
F 1 6
E 2 3
E 1 2
E 1 3
U 1 4
F 1 5
U 1 6
F 1 6
Out: Example XX: 4.400
C producer code:
[Cpp]
# Include <stdio. h>
# Include <iostream>
# Include <string. h>
# Include <set>
# Include <algorithm>
Using namespace std;
# Deprecision MAX 20010
# Define PAIR pair <int, int>
Struct Query {
Char ope [3];
Int x, y;
} Query [2, 300010];
Double ans;
Int cost [MAX]; // cost [I] indicates the weight of each vertex.
Int n, m, q, time, fa [MAX]; // fa [I] indicates which set I belongs
Multiset <int> map [MAX]; // stores graphs. In this case, an undirected graph is converted to a directed graph, because you only need to determine whether the graph is connected.
Multiset <int> ver [MAX]; // stores all nodes whose father is a certain Node
Int GetPa (int x) {// obtain the father of x and compress the path
Int p = x, tp;
While (p! = Fa [p]) p = fa [p];
While (x! = P ){
Tp = fa [x];
Fa [x] = p, x = tp;
}
Return p;
}
Void UnionSet (int x, int y) {// merge the set of y and the set of x
Int px = GetPa (x );
Int py = GetPa (y );
If (px = py) return;
If (px> py) swap (px, py );
Fa [px] = py;
Multiset <int >:: iterator it;
For (it = ver [px]. begin (); it! = Ver [px]. end (); ++ it)
Ver [py]. insert (* it); // when merging, the child nodes also need to be merged.
}
Int main ()
{
Int I, j, k, cas = 0, a, B, pa;
While (scanf ("% d", & n, & m, & q )! = EOF ){
For (I = 1; I <= n; ++ I ){
Fa [I] = I;
Map [I]. clear ();
Ver [I]. clear ();
Scanf ("% d", & cost [I]);
}
For (I = 1; I <= m; ++ I ){
Scanf ("% d", & a, & B); // the edge is connected from a small vertex to a large vertex.
If (a <B) map [a]. insert (B );
Else map [B]. insert ();
}
For (I = 1; I <= q; ++ I) {// process all operations first, query back, and add edge
Scanf ("% s % d", query [I]. ope, & a, & B );
Query [I]. x = a, query [I]. y = B;
If (query [I]. ope [0] = 'U '){
// Save the original vertex right and update the vertex right
Query [I]. y = cost [a];
Cost [a] = B;
}
Else if (query [I]. ope [0] = 'E '){
// Delete this edge first and then add it later. This eliminates the need to split the set.
If (a <B) map [a]. erase (map [a]. find (B ));
Else map [B]. erase (map [B]. find ());
}
}
For (I = 1; I <= n; ++ I)
Ver [I]. insert (cost [I]);
Multiset <int >:: iterator it;
For (I = 1; I <= n; ++ I) // use the processed graph to create and query the set.
For (it = map [I]. begin (); it! = Map [I]. end (); ++ it)
UnionSet (I, * it );
Ans = time = 0;
For (I = q; I> = 1; -- I ){
A = query [I]. x, B = query [I]. y;
If (query [I]. ope [0] = 'F '){
Time ++, pa = GetPa ();
It = ver [pa]. lower_bound (B); // This method of set is suitable for query operations.
If (it! = Ver [pa]. end () ans + = * it;
}
Else if (query [I]. ope [0] = 'U '){
// Update back
Pa = GetPa ();
It = ver [pa]. find (cost [a]);
Ver [pa]. erase (it );
Ver [pa]. insert (B );
Cost [a] = B;
} Www.2cto.com
Else UnionSet (a, B); // this step is a key benefit of reverse processing and becomes abnormal and simple.
}
Printf ("Case % d: %. 3lf \ n", ++ cas, ans/time );
}
}
Author: woshi250hua