Codeforces292D(SummerTrainingDay06-L 前缀并查集)
D. Connected Components
We already know of the large corporation where Polycarpus works as a system administrator. The computer network there consists of n computers and m cables that connect some pairs of computers. In other words, the computer network can be represented as some non-directed graph with n nodes and m edges. Let's index the computers with integers from 1 to n, let's index the cables with integers from 1 to m.
Polycarpus was given an important task — check the reliability of his company's network. For that Polycarpus decided to carry out a series of k experiments on the computer network, where the i-th experiment goes as follows:
- Temporarily disconnect the cables with indexes from li to ri, inclusive (the other cables remain connected).
- Count the number of connected components in the graph that is defining the computer network at that moment.
- Re-connect the disconnected cables with indexes from li to ri (that is, restore the initial network).
Help Polycarpus carry out all experiments and for each print the number of connected components in the graph that defines the computer network through the given experiment. Isolated vertex should be counted as single component.
Input
The first line contains two space-separated integers n, m (2 ≤ n ≤ 500; 1 ≤ m ≤ 104) — the number of computers and the number of cables, correspondingly.
The following m lines contain the cables' description. The i-th line contains space-separated pair of integers xi, yi(1 ≤ xi, yi ≤ n; xi ≠ yi) — the numbers of the computers that are connected by the i-th cable. Note that a pair of computers can be connected by multiple cables.
The next line contains integer k (1 ≤ k ≤ 2·104) — the number of experiments. Next k lines contain the experiments' descriptions. The i-th line contains space-separated integers li, ri (1 ≤ li ≤ ri ≤ m) — the numbers of the cables that Polycarpus disconnects during the i-th experiment.
Output
Print k numbers, the i-th number represents the number of connected components of the graph that defines the computer network during the i-th experiment.
Examples
input
6 5
1 2
5 4
2 3
3 1
3 6
6
1 3
2 5
1 5
5 5
2 4
3 3
output
4
5
6
3
4
2
题意:给出n(<=500)个点和m(<=1e4)条边,形成一个图,查询k(<=1e4)次,对于每个查询,有l和r,输出删除编号[l,r]区间内的边后形成的连通块的个数。
思路:连通块肯定想到用并查集去维护。然后看到n比较小,所以可能可以每次查询里面复杂度带有n。
因为删边用并查集不是很好维护,所以我们可能要想到能不能避免边的删除,那么很容易的想到前缀和思想。
用dsu1[l]来保存[1,l]前l条边组成的图里面的并查集父节点的情况;
用dsu2[r]来保存[r,n]后r条边组成的图里面的并查集父节点的情况;
那么对于每一次查询[l,r]我只要把dsu1[l-1]和dsu2[r+1]的并查集父节点情况再次合并,也就是把两个并查集数组合并,那么就能得到新的并查集,这就是此刻图的情况了。
1 //=============================================// 2 // _ooOoo_ // 3 // o8888888o // 4 // 88" . "88 // 5 // (| -_- |) // 6 // O\ = /O // 7 // ____/`---'\____ // 8 // .' \\| |// `. // 9 // / \\||| : |||// \ // 10 // / _||||| -:- |||||- \ // 11 // | | | \\\ - /// | | | // 12 // | \_| ''\---/'' | / | // 13 // \ .-\__ `-` ___/-. / // 14 // ___`. .' /--.--\ `. . __ // 15 // ."" '< `.___\_<|>_/___.' >'"". // 16 // | | : `- \`.;`\ _ /`;.`/ - `: | | // 17 // \ \ `-. \_ __\ /__ _/ .-` / / // 18 //======`-.____`-.___\_____/___.-`____.-'======// 19 // `=---=' // 20 //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^// 21 // 佛祖保佑 永无BUG // 22 // 本模块已经经过开光处理,绝无可能再产生bug // 23 //=============================================// 24 //2017-09-05 25 #include <cstdio> 26 #include <cstring> 27 #include <iostream> 28 #include <algorithm> 29 30 using namespace std; 31 32 const int N = 520; 33 const int M = 11000; 34 35 int n, m; 36 struct DSU{ 37 int fa[N]; 38 void init(){ 39 for(int i = 0; i < N; i++) 40 fa[i] = i; 41 } 42 int getfa(int x){ 43 if(x == fa[x])return x; 44 return fa[x] = getfa(fa[x]); 45 } 46 void merge(int a, int b){ 47 int af = getfa(a); 48 int bf = getfa(b); 49 if(af != bf){ 50 fa[bf] = af; 51 } 52 } 53 }dsu1[M], dsu2[M];//dsu1[i]表示由前i条边生成的并查集,dsu2[i]表示由后i条边生成的并查集 54 55 int work(DSU ldsu, DSU rdsu){ 56 //将两棵并查集合并 57 for(int i = 1; i <= n; i++) 58 ldsu.merge(i, rdsu.getfa(i)); 59 int ans = 0; 60 for(int i = 1; i <= n; i++) 61 if(ldsu.fa[i] == i) 62 ans++; 63 return ans; 64 } 65 pair<int, int> line[M]; 66 int main() 67 { 68 std::ios::sync_with_stdio(false); 69 cin.tie(0); 70 //freopen("inputL.txt", "r", stdin); 71 while(cin>>n>>m){ 72 for(int i = 1; i <= m; i++) 73 cin>>line[i].first>>line[i].second; 74 dsu1[0].init(); 75 for(int i = 1; i <= m; i++){ 76 dsu1[i] = dsu1[i-1]; 77 dsu1[i].merge(line[i].first, line[i].second); 78 } 79 dsu2[m+1].init(); 80 for(int i = m; i >= 1; i--){ 81 dsu2[i] = dsu2[i+1]; 82 dsu2[i].merge(line[i].first, line[i].second); 83 } 84 int k, l, r; 85 cin>>k; 86 while(k--){ 87 cin>>l>>r; 88 cout<<work(dsu1[l-1], dsu2[r+1])<<endl; 89 } 90 } 91 92 return 0; 93 }