某模拟题题解
第一道题还是比较简单,只不过做的时候手贱写错了一个字母,然后活活RE掉了40分
先处理处最终的图,然后从后往前用并查集完成询问。至于之前的删边可以排个序,
然后建一个长度和它一样的boolean数组标志这条边又没被删,删除的时候就lower_bound
就可以了,只不过注意重复的边。如果这一位上为false(这条边被删掉了)应该往后找到
第一个为true的地方,然后将它改为false
Code
1 #include<iostream> 2 #include<cstdio> 3 #include<fstream> 4 #include<cstdlib> 5 #include<queue> 6 #include<set> 7 #include<map> 8 #include<cctype> 9 #include<algorithm> 10 #include<cstring> 11 #include<string> 12 #include<stack> 13 using namespace std; 14 typedef bool boolean; 15 #define smin(a, b) a = min(a, b) 16 #define smax(a, b) b = max(a, b) 17 template<typename T> 18 inline void readInteger(T& u) { 19 char x; 20 while(!isdigit(x = getchar())); 21 for(u = x - '0'; isdigit((x = getchar())); u = (u << 3) + (u << 1) + x - '0'); 22 ungetc(x, stdin); 23 } 24 25 typedef class union_found{ 26 public: 27 int *f; 28 union_found():f(NULL) {} 29 union_found(int points) { 30 f = new int[(const int)(points + 1)]; 31 for(int i = 0; i <= points; i++) 32 f[i] = i; 33 } 34 int find(int x) { 35 if(f[x] != x) return f[x] = find(f[x]); 36 return f[x]; 37 } 38 void unit(int fa, int so) { 39 int ffa = find(fa); 40 int fso = find(so); 41 f[fso] = ffa; 42 } 43 boolean connected(int a, int b) { 44 return find(a) == find(b); 45 } 46 }union_found; 47 48 typedef class _edge{ 49 public: 50 int from; 51 int end; 52 _edge(const int a = 0, const int b = 0) { 53 from = min(a, b); 54 end = max(a, b); 55 } 56 boolean operator <(_edge another) const { 57 if(this->from != another.from) return this->from < another.from; 58 return this->end < another.end; 59 } 60 }_edge; 61 62 typedef class _question{ 63 public: 64 boolean isCut; 65 int a; 66 int b; 67 }_question; 68 69 inline void readQues(_question& que){ 70 int c; 71 readInteger(c); 72 if(c == 1) que.isCut = true; 73 else que.isCut = false; 74 readInteger(que.a); 75 readInteger(que.b); 76 } 77 78 int n, m, q; 79 union_found uf; 80 _edge* es; 81 boolean* enable; 82 _question *ques; 83 stack<int> s; 84 85 #define MAP_IT multiset<_edge>::iterator 86 87 inline void init() { 88 int lastEdge; 89 readInteger(n); 90 readInteger(m); 91 readInteger(q); 92 es = new _edge[(const int)(m + 1)]; 93 uf = union_found(n); 94 ques = new _question[(const int)(q + 1)]; 95 enable = new boolean[(const int)(m + 1)]; 96 lastEdge = m; 97 memset(enable, true, sizeof(boolean) * (m + 1)); 98 for(int i = 1, a, b; i <= m; i++){ 99 readInteger(a); 100 readInteger(b); 101 es[i] = _edge(a, b); 102 } 103 sort(es + 1, es + m + 1); 104 for(int i = 1; i <= q; i++){ 105 readQues(ques[i]); 106 ques[i].a ^= lastEdge; 107 ques[i].b ^= lastEdge; 108 if(ques[i].isCut){ 109 // es.erase(es.lower_bound(_edge(ques[i].a, ques[i].b))); 110 int rank = lower_bound(es + 1, es + m + 1, _edge(ques[i].a, ques[i].b)) - es; 111 while(!enable[rank]) rank++; 112 enable[rank] = false; 113 lastEdge--; 114 } 115 } 116 for(int i = 1; i <= m; i++){ 117 if(enable[i]) 118 uf.unit(es[i].from, es[i].end); 119 } 120 } 121 122 void solve() { 123 for(int i = q; i > 0; i--){ 124 if(ques[i].isCut){ 125 uf.unit(ques[i].a, ques[i].b); 126 }else{ 127 boolean result = uf.connected(ques[i].a, ques[i].b); 128 if(result) s.push(1); 129 else s.push(0); 130 } 131 } 132 while(!s.empty()){ 133 printf("%d\n", s.top()); 134 s.pop(); 135 } 136 } 137 138 int main(){ 139 freopen("graph.in", "r", stdin); 140 freopen("graph.out", "w", stdout); 141 init(); 142 solve(); 143 fclose(stdin); 144 fclose(stdout); 145 return 0; 146 }
第二道相对于第一道题就没有那么友好了,这次真的只能用在线算法,于是我决定用暴力碰碰运气
结果真的AC了。。。(这数据太水,没办法)
思路很简单,这道题是树,所以,两点之间的连线断开后,就成了两个联通块,然后我给每个连通块
一个编号,然后每次删边就去dfs一遍修改这个值。
2018-2-17
现在想了想,其实直接写一个LCT没多大毛病。
记得标程用的树链剖分。于是考虑树链剖分怎么做。
对于删边操作,如果删掉的是轻边,那么只需要更改father信息,如果删掉的是重边,那么需要修改重链上一段的重链顶,这个可以用线段树来维护。
对于查询操作,两个点沿着重链一直往上跳,看最后跳到的点是否相同就可以判断联通了。
Code
1 #include<iostream> 2 #include<cstdio> 3 #include<fstream> 4 #include<cstdlib> 5 #include<queue> 6 #include<set> 7 #include<map> 8 #include<cctype> 9 #include<algorithm> 10 #include<cstring> 11 #include<string> 12 using namespace std; 13 typedef bool boolean; 14 #define smin(a, b) a = min(a, b) 15 #define smax(a, b) b = max(a, b) 16 template<typename T> 17 inline void readInteger(T& u) { 18 char x; 19 while(!isdigit(x = getchar())); 20 for(u = x - '0'; isdigit((x = getchar())); u = (u << 3) + (u << 1) + x - '0'); 21 ungetc(x, stdin); 22 } 23 24 ///Linked Map Template Starts 25 typedef class Edge{ 26 public: 27 int next; 28 int end; 29 Edge(const int next = 0, const int end = 0):next(next), end(end){ } 30 }Edge; 31 typedef class MapManager{ 32 public: 33 int *h; 34 Edge* edge; 35 int ce; 36 MapManager():h(NULL), edge(NULL), ce(0) { } 37 MapManager(int point, int edges):ce(0){ 38 h = new int[(const int)(point + 1)]; 39 edge = new Edge[(const int)(edges + 1)]; 40 memset(h, 0, sizeof(int) * (point + 1)); 41 } 42 inline void addEdge(int from, int end) { 43 edge[++ce] = Edge(h[from], end); 44 h[from] = ce; 45 } 46 }MapManager; 47 ///Linked Map Template Ends 48 49 int n, q; 50 MapManager tree; 51 int* fa; 52 int* value; 53 int* types; 54 int ct; 55 56 inline void init() { 57 ct = 1; 58 readInteger(n); 59 readInteger(q); 60 value = new int[(const int)(n + 1)]; 61 fa = new int[(const int)(n + 1)]; 62 tree = MapManager(n, 2 * n); 63 types = new int[(const int)(n + 1)]; 64 fill(types + 1, types + n + 1, 1); 65 for(int i = 1; i <= n; i++) readInteger(value[i]); 66 for(int i = 1, a, b; i < n; i++){ 67 readInteger(a); 68 readInteger(b); 69 tree.addEdge(a, b); 70 tree.addEdge(b, a); 71 } 72 } 73 74 void buildTree(int node, int lastNode){ 75 fa[node] = lastNode; 76 for(int i = tree.h[node]; i != 0; i = tree.edge[i].next){ 77 int& end = tree.edge[i].end; 78 if(end == lastNode) continue; 79 buildTree(end, node); 80 } 81 } 82 83 void update(int node, int lastNode, const int newType){ 84 if(fa[node] != lastNode) return; 85 types[node] = newType; 86 for(int i = tree.h[node]; i != 0; i = tree.edge[i].next){ 87 int& end = tree.edge[i].end; 88 if(end == lastNode) continue; 89 update(end, node, newType); 90 } 91 } 92 93 int lastans; 94 95 inline void solve() { 96 buildTree(1, 0); 97 for(int i = 1, c, a, b; i <= q; i++){ 98 readInteger(c); 99 readInteger(a); 100 readInteger(b); 101 a ^= lastans; 102 b ^= lastans; 103 int s; 104 switch(c){ 105 case 1: 106 if(fa[a] == b){ 107 s = a; 108 }else{ 109 s = b; 110 } 111 fa[s] = 0; 112 update(s, 0, ++ct); 113 break; 114 case 2: 115 if(types[a] == types[b]){ 116 lastans = value[a] * value[b]; 117 } else { 118 lastans = value[a] + value[b]; 119 } 120 printf("%d\n", lastans); 121 break; 122 case 3: 123 value[a] = b; 124 break; 125 default: 126 // throw c; 127 break; 128 } 129 } 130 } 131 132 int main(){ 133 freopen("tree.in", "r", stdin); 134 freopen("tree.out", "w", stdout); 135 init(); 136 solve(); 137 return 0; 138 }
第三题,也是最简单的一道,直接Tarjan搜强连通分量不解释
Code
1 #include<iostream> 2 #include<cstdio> 3 #include<fstream> 4 #include<cstdlib> 5 #include<queue> 6 #include<set> 7 #include<map> 8 #include<stack> 9 #include<cctype> 10 #include<algorithm> 11 #include<cstring> 12 #include<string> 13 using namespace std; 14 typedef bool boolean; 15 #define smin(a, b) a = min(a, b) 16 #define smax(a, b) b = max(a, b) 17 template<typename T> 18 inline void readInteger(T& u) { 19 char x; 20 while(!isdigit(x = getchar())); 21 for(u = x - '0'; isdigit((x = getchar())); u = (u << 3) + (u << 1) + x - '0'); 22 ungetc(x, stdin); 23 } 24 ///Linked Map Template Starts 25 typedef class Edge{ 26 public: 27 int next; 28 int end; 29 Edge(const int next = 0, const int end = 0):next(next), end(end){ } 30 }Edge; 31 typedef class MapManager{ 32 public: 33 int *h; 34 Edge* edge; 35 int ce; 36 MapManager():h(NULL), edge(NULL), ce(0) { } 37 MapManager(int point, int edges):ce(0){ 38 h = new int[(const int)(point + 1)]; 39 edge = new Edge[(const int)(edges + 1)]; 40 memset(h, 0, sizeof(int) * (point + 1)); 41 } 42 inline void addEdge(int from, int end) { 43 edge[++ce] = Edge(h[from], end); 44 h[from] = ce; 45 } 46 }MapManager; 47 ///Linked Map Template Ends 48 49 MapManager g; 50 long long result; 51 52 stack<int> s; 53 boolean* visited; 54 boolean* inStack; 55 int counter; 56 int *visitID; 57 int *exitID; 58 59 inline void getMap(int end){ 60 int c_m = 0; 61 int node; 62 do{ 63 node = s.top(); 64 s.pop(); 65 inStack[node] = false; 66 c_m++; 67 }while(node != end); 68 result += c_m * 1LL * (c_m - 1) / 2; 69 } 70 71 void Tarjan(int node){ 72 visited[node] = true; 73 visitID[node] = exitID[node] = ++counter; 74 s.push(node); 75 inStack[node] = true; 76 for(int i = g.h[node]; i != 0; i = g.edge[i].next){ 77 int e = g.edge[i].end; 78 if(!visited[e]) { 79 Tarjan(e); 80 smin(exitID[node], exitID[e]); 81 } else if(inStack[e]) { 82 smin(exitID[node], visitID[e]); 83 } 84 } 85 if(visitID[node] == exitID[node]) 86 getMap(node); 87 } 88 89 int n; 90 int m; 91 92 inline void init() { 93 readInteger(n); 94 readInteger(m); 95 g = MapManager(n, m); 96 visited = new boolean[(const int)(n + 1)]; 97 inStack = new boolean[(const int)(n + 1)]; 98 visitID = new int[(const int)(n + 1)]; 99 exitID = new int[(const int)(n + 1)]; 100 memset(visited, false, sizeof(boolean) * (n + 1)); 101 memset(inStack, false, sizeof(boolean) * (n + 1)); 102 for(int i = 1, a, b; i <= m; i++) { 103 readInteger(a); 104 readInteger(b); 105 g.addEdge(a, b); 106 } 107 } 108 109 inline void solve() { 110 for(int i = 1; i <= n; i++) { 111 if(!visited[i]) 112 Tarjan(i); 113 } 114 cout<<result; 115 } 116 117 int main(){ 118 freopen("logic.in", "r", stdin); 119 freopen("logic.out", "w", stdout); 120 init(); 121 solve(); 122 return 0; 123 }