薛的lca讲课配到题解
2.15 LCA
Nearest Common Ancestors POJ 1330
题意:给出一棵树, 询问两个点的最近公共祖先。
思路:
$LCA$模板题,请各位掏出各式各样的模板A穿它。
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 #include<cmath> 5 #include<queue> 6 7 using namespace std; 8 9 typedef long long ll; 10 const int maxn = 1e4 + 10; 11 const int DEG = 20; 12 13 struct Edge { 14 int to, nxt; 15 Edge() {} 16 Edge(int to, int nxt) :to(to), nxt(nxt) {} 17 }edge[maxn << 1]; 18 19 int head[maxn], tot; 20 21 void Init() 22 { 23 tot = 0; 24 memset(head, -1, sizeof head); 25 } 26 27 void addedge(int u, int v) 28 { 29 edge[tot] = Edge(v, head[u]); head[u] = tot++; 30 edge[tot] = Edge(u, head[v]); head[v] = tot++; 31 } 32 33 int fa[maxn][DEG]; 34 int deg[maxn]; 35 36 void BFS(int root) 37 { 38 queue<int>q; 39 deg[root] = 0; 40 fa[root][0] = root; 41 q.push(root); 42 while (!q.empty()) 43 { 44 int tmp = q.front(); 45 q.pop(); 46 for (int i = 1; i < DEG; ++i) 47 { 48 fa[tmp][i] = fa[fa[tmp][i - 1]][i - 1]; 49 } 50 for (int i = head[tmp]; i != -1; i = edge[i].nxt) 51 { 52 int v = edge[i].to; 53 if (v == fa[tmp][0]) continue; 54 deg[v] = deg[tmp] + 1; 55 fa[v][0] = tmp; 56 q.push(v); 57 } 58 } 59 } 60 61 int LCA(int u, int v) 62 { 63 if (deg[u] > deg[v]) swap(u, v); 64 int hu = deg[u]; 65 int hv = deg[v]; 66 int tu = u, tv = v; 67 for (int det = hv - hu, i = 0; det; det >>= 1, ++i) 68 { 69 if (det & 1) 70 { 71 tv = fa[tv][i]; 72 } 73 } 74 if (tu == tv) return tu; 75 for (int i = DEG - 1; i >= 0; --i) 76 { 77 if (fa[tu][i] == fa[tv][i]) 78 continue; 79 tu = fa[tu][i]; 80 tv = fa[tv][i]; 81 } 82 return fa[tu][0]; 83 } 84 85 int n; 86 bool flag[maxn]; 87 88 void RUN() 89 { 90 int t; 91 scanf("%d", &t); 92 while (t--) 93 { 94 scanf("%d", &n); 95 Init(); 96 memset(flag, false, sizeof flag); 97 for (int i = 1; i < n; ++i) 98 { 99 int u, v; 100 ll w; 101 scanf("%d %d", &u, &v); 102 addedge(u, v); 103 flag[v] = true; 104 } 105 int root = 0; 106 for (int i = 1; i <= n; ++i) 107 { 108 if (!flag[i]) 109 { 110 root = i; 111 break; 112 } 113 } 114 BFS(root); 115 int u, v; 116 scanf("%d %d", &u, &v); 117 printf("%d\n", LCA(u, v)); 118 } 119 } 120 121 int main() 122 { 123 #ifdef LOCAL_JUDGE 124 freopen("Text.txt", "r", stdin); 125 #endif // LOCAL_JUDGE 126 127 RUN(); 128 129 #ifdef LOCAL_JUDGE 130 fclose(stdin); 131 #endif // LOCAL_JUDGE 132 return 0; 133 }
Closest Common Ancestors POJ 1470
题意:给出一棵树,然后给出几组询问,记录每个点作为询问中的最近公共祖先的次数并输出,如果次数为0则不输出。
思路:
$LCA$模板题,建图稍微注意一下后对于每次询问都记录他的最近最近公共祖先,输出。
1 #include<cstdio> 2 #include<iostream> 3 #include<cmath> 4 #include<cstring> 5 #include<algorithm> 6 #include<queue> 7 8 using namespace std; 9 10 typedef long long ll; 11 const int maxn = 1e5 + 10; 12 const int DEG = 20; 13 14 struct Edge { 15 int to, nxt; 16 Edge() {} 17 Edge(int to, int nxt) :to(to), nxt(nxt) {} 18 }edge[maxn << 1]; 19 20 int head[maxn], tot; 21 22 int dis[maxn]; 23 24 void addedge(int u, int v) 25 { 26 edge[tot] = Edge(v, head[u]); 27 head[u] = tot++; 28 } 29 30 void Init() 31 { 32 tot = 0; 33 memset(head, -1, sizeof head); 34 } 35 36 int fa[maxn][DEG]; 37 int deg[maxn]; 38 39 void BFS(int root) 40 { 41 queue<int>q; 42 deg[root] = 0; 43 fa[root][0] = root; 44 q.push(root); 45 while (!q.empty()) 46 { 47 int tmp = q.front(); 48 q.pop(); 49 for (int i = 1; i < DEG; ++i) 50 { 51 fa[tmp][i] = fa[fa[tmp][i - 1]][i - 1]; 52 } 53 for (int i = head[tmp]; i != -1; i = edge[i].nxt) 54 { 55 int v = edge[i].to; 56 if (v == fa[tmp][0]) continue; 57 deg[v] = deg[tmp] + 1; 58 fa[v][0] = tmp; 59 q.push(v); 60 } 61 } 62 } 63 64 int LCA(int u, int v) 65 { 66 if (deg[u] > deg[v]) swap(u, v); 67 int hu = deg[u]; 68 int hv = deg[v]; 69 int tu = u, tv = v; 70 for (int det = hv - hu, i = 0; det; det >>= 1, ++i) 71 { 72 if (det & 1) 73 { 74 tv = fa[tv][i]; 75 } 76 } 77 if (tu == tv) return tu; 78 for (int i = DEG - 1; i >= 0; --i) 79 { 80 if (fa[tu][i] == fa[tv][i]) 81 continue; 82 tu = fa[tu][i]; 83 tv = fa[tv][i]; 84 } 85 return fa[tu][0]; 86 } 87 88 int n, m; 89 char str[maxn]; 90 bool flag[maxn]; 91 int arr[maxn]; 92 93 void RUN() 94 { 95 while (~scanf("%d", &n)) 96 { 97 Init(); 98 memset(flag, false, sizeof flag); 99 memset(arr, 0, sizeof arr); 100 for (int i = 1; i <= n; ++i) 101 { 102 int id, m; 103 scanf("%d:(%d)", &id, &m); 104 for (int i = 0; i < m; ++i) 105 { 106 int id2; 107 scanf("%d", &id2); 108 addedge(id, id2); 109 flag[id2] = true; 110 } 111 } 112 int root = 0; 113 for (int i = 1; i <= n; ++i) 114 { 115 if (!flag[i]) 116 { 117 root = i; 118 break; 119 } 120 } 121 BFS(root); 122 int q; 123 scanf("%d", &q); 124 while (q--) 125 { 126 int u, v; 127 scanf(" (%d %d)", &u, &v); 128 int root = LCA(u, v); 129 arr[root]++; 130 } 131 for (int i = 1; i <= n; ++i) 132 { 133 if (arr[i]) 134 { 135 printf("%d:%d\n", i, arr[i]); 136 } 137 } 138 } 139 } 140 141 int main() 142 { 143 #ifdef LOCAL_JUDGE 144 freopen("Text.txt", "r", stdin); 145 #endif // LOCAL_JUDGE 146 147 RUN(); 148 149 #ifdef LOCAL_JUDGE 150 fclose(stdin); 151 #endif // LOCAL_JUDGE 152 return 0; 153 }
How far away ?HDU 2586
题意:给出一棵树,每条边有边权,然后给出几组询问,每组询问需要输出$u, v$之间的最短路径。
思路:
对于一棵树,两个点的路径唯一。
这两个点的路径长度为u到根的路径长度加上v到根的路径长度减去两倍LCA(u, v)到根的路径长度。
即$dis_u+dis_v-2 \cdot dis_{LCA_{u, v}}$。
1 #include<bits/stdc++.h> 2 3 using namespace std; 4 5 typedef long long ll; 6 7 const int maxn = 1e5 + 10; 8 const int DEG = 20; 9 10 int dis[maxn]; 11 12 struct Edge { 13 int to; 14 int next; 15 int w; 16 Edge() {} 17 Edge(int to, int next, int w) :to(to), next(next), w(w) {} 18 }edge[maxn << 1]; 19 20 int head[maxn]; 21 int tot; 22 23 void addedge(int u, int v, int w) 24 { 25 edge[tot] = Edge(v, head[u], w); 26 head[u] = tot++; 27 } 28 29 void init() 30 { 31 tot = 0; 32 memset(head, -1, sizeof head); 33 memset(dis, 0x3f, sizeof dis); 34 } 35 36 int fa[maxn][DEG]; 37 int deg[maxn]; 38 39 void BFS(int root) 40 { 41 queue<int>q; 42 deg[root] = 0; 43 fa[root][0] = root; 44 q.push(root); 45 dis[root] = 0; 46 while (!q.empty()) 47 { 48 int tmp = q.front(); 49 q.pop(); 50 for (int i = 1; i < DEG; ++i) 51 { 52 fa[tmp][i] = fa[fa[tmp][i - 1]][i - 1]; 53 } 54 for (int i = head[tmp]; i != -1; i = edge[i].next) 55 { 56 int v = edge[i].to; 57 if (v == fa[tmp][0]) continue; 58 dis[v] = dis[tmp] + edge[i].w; 59 deg[v] = deg[tmp] + 1; 60 fa[v][0] = tmp; 61 q.push(v); 62 } 63 } 64 } 65 66 int LCA(int u, int v) 67 { 68 if (deg[u] > deg[v]) 69 swap(u, v); 70 int hu = deg[u], hv = deg[v]; 71 int tu = u; 72 int tv = v; 73 for (int det = hv - hu, i = 0; det; det >>= 1, ++i) 74 { 75 if (det & 1) 76 { 77 tv = fa[tv][i]; 78 } 79 } 80 if (tu == tv) return tu; 81 for (int i = DEG - 1; i >= 0; --i) 82 { 83 if (fa[tu][i] == fa[tv][i]) 84 continue; 85 tu = fa[tu][i]; 86 tv = fa[tv][i]; 87 } 88 return fa[tu][0]; 89 } 90 91 void RUN() 92 { 93 int t; 94 scanf("%d", &t); 95 while (t--) 96 { 97 init(); 98 int n, q; 99 scanf("%d %d", &n, &q); 100 for (int i = 1; i < n; ++i) 101 { 102 int u, v, w; 103 scanf("%d %d %d", &u, &v, &w); 104 addedge(u, v, w); 105 addedge(v, u, w); 106 } 107 BFS(1); 108 while (q--) 109 { 110 int u, v; 111 scanf("%d %d", &u, &v); 112 int root = LCA(u, v); 113 int ans = dis[u] + dis[v] - 2 * dis[root]; 114 printf("%d\n", ans); 115 } 116 } 117 } 118 119 int main() 120 { 121 #ifdef LOCAL_JUDGE 122 freopen("Text.txt", "r", stdin); 123 #endif // LOCAL_JUDGE 124 125 RUN(); 126 127 #ifdef LOCAL_JUDGE 128 fclose(stdin); 129 #endif // LOCAL_JUDGE 130 return 0; 131 }
Connections between cities HDU 2874
题意:给出一张图,保证无环,但是不保证连通,求出两个点的最短距离,如果不连通就输出$"Not connected"$。
思路:
由于保证无环,那么给出的图就是一颗或者多颗树。
那么可以用并查集来维护两点是否在一个集合中,也就是一棵树中。
对于在一棵树上的$u,v$两点,距离就是$dis_u+dis_v-2 \cdot dis_{LCA_{u, v}}$。
1 #include<bits/stdc++.h> 2 3 using namespace std; 4 5 typedef long long ll; 6 7 const int maxn = 1e5 + 10; 8 const int DEG = 20; 9 10 int n, m, q; 11 int Fa[maxn]; 12 13 int dis[maxn]; 14 15 int find(int x) 16 { 17 return x == Fa[x] ? Fa[x] : Fa[x] = find(Fa[x]); 18 } 19 20 void mix(int x, int y) 21 { 22 x = find(x); 23 y = find(y); 24 if (x != y) 25 { 26 Fa[x] = y; 27 } 28 } 29 30 struct Edge { 31 int to; 32 int next; 33 int w; 34 Edge() {} 35 Edge(int to, int next, int w) :to(to), next(next), w(w) {} 36 }edge[maxn << 1]; 37 38 int head[maxn]; 39 int tot; 40 41 void addedge(int u, int v, int w) 42 { 43 edge[tot] = Edge(v, head[u], w); 44 head[u] = tot++; 45 } 46 47 void init() 48 { 49 tot = 0; 50 memset(head, -1, sizeof head); 51 memset(dis, 0, sizeof dis); 52 for (int i = 1; i <= n; ++i) 53 { 54 Fa[i] = i; 55 } 56 } 57 58 int fa[maxn][DEG]; 59 int deg[maxn]; 60 61 void BFS() 62 { 63 queue<int>q; 64 for (int i = 1; i <= n; ++i) 65 { 66 if (find(i) == i) 67 { 68 deg[i] = 0; 69 fa[i][0] = i; 70 dis[i] = 0; 71 q.push(i); 72 } 73 } 74 while (!q.empty()) 75 { 76 int tmp = q.front(); 77 q.pop(); 78 for (int i = 1; i < DEG; ++i) 79 { 80 fa[tmp][i] = fa[fa[tmp][i - 1]][i - 1]; 81 } 82 for (int i = head[tmp]; i != -1; i = edge[i].next) 83 { 84 int v = edge[i].to; 85 if (v == fa[tmp][0]) continue; 86 dis[v] = dis[tmp] + edge[i].w; 87 deg[v] = deg[tmp] + 1; 88 fa[v][0] = tmp; 89 q.push(v); 90 } 91 } 92 } 93 94 int LCA(int u, int v) 95 { 96 if (deg[u] > deg[v]) 97 swap(u, v); 98 int hu = deg[u], hv = deg[v]; 99 int tu = u; 100 int tv = v; 101 for (int det = hv - hu, i = 0; det; det >>= 1, ++i) 102 { 103 if (det & 1) 104 { 105 tv = fa[tv][i]; 106 } 107 } 108 if (tu == tv) return tu; 109 for (int i = DEG - 1; i >= 0; --i) 110 { 111 if (fa[tu][i] == fa[tv][i]) 112 continue; 113 tu = fa[tu][i]; 114 tv = fa[tv][i]; 115 } 116 return fa[tu][0]; 117 } 118 119 void solve() 120 { 121 int u, v; 122 scanf("%d %d", &u, &v); 123 int rootu = find(u); 124 int rootv = find(v); 125 if (rootu != rootv) 126 { 127 puts("Not connected"); 128 return; 129 } 130 int root = LCA(u, v); 131 int ans = dis[u] + dis[v] - 2 * dis[root]; 132 printf("%d\n", ans); 133 } 134 135 void RUN() 136 { 137 while (~scanf("%d %d %d", &n, &m, &q)) 138 { 139 init(); 140 for (int i = 0; i < m; ++i) 141 { 142 int u, v, w; 143 scanf("%d %d %d", &u, &v, &w); 144 addedge(u, v, w); 145 addedge(v, u, w); 146 mix(u, v); 147 } 148 BFS(); 149 while (q--) 150 { 151 solve(); 152 } 153 } 154 } 155 156 int main() 157 { 158 #ifdef LOCAL_JUDGE 159 freopen("Text.txt", "r", stdin); 160 #endif // LOCAL_JUDGE 161 162 RUN(); 163 164 #ifdef LOCAL_JUDGE 165 fclose(stdin); 166 #endif // LOCAL_JUDGE 167 return 0; 168 }
Network POJ - 3417
题意:给出一棵树和一些非树边,你可以选择破坏一条树边以及一条非树边,问有多少种方式可以破坏这棵树。
思路:
对于每条非树边$u-v$都可以形成一个$u-LCA_{u, v}-v-u$的环,如果破坏这个这个环则只能选择环上一个树边以及新加入的非树边。
如果某条树边被多个环覆盖那么无法通过破坏这条边以及非树边来破坏整棵树。
如果某条树边没有被环覆盖那么可以通过破坏这条树边以及任意一条非树边来破坏整棵树。
最后可以通过$LCA$以及树上差分(前缀和?)来优化求出每条树边被多少个环覆盖。
1 #include<cstdio> 2 #include<iostream> 3 #include<cmath> 4 #include<cstring> 5 #include<algorithm> 6 #include<queue> 7 8 using namespace std; 9 10 typedef long long ll; 11 const int maxn = 1e6 + 10; 12 const int DEG = 20; 13 14 struct Edge { 15 int to, nxt; 16 Edge() {} 17 Edge(int to, int nxt) :to(to), nxt(nxt) {} 18 }edge[maxn << 1]; 19 20 int head[maxn], tot; 21 22 int dis[maxn]; 23 24 void addedge(int u, int v) 25 { 26 edge[tot] = Edge(v, head[u]); 27 head[u] = tot++; 28 } 29 30 void init() 31 { 32 memset(head, -1, sizeof head); 33 tot = 0; 34 } 35 36 int fa[maxn][DEG]; 37 int deg[maxn]; 38 39 void BFS(int root) 40 { 41 queue<int>q; 42 deg[root] = 0; 43 fa[root][0] = root; 44 q.push(root); 45 while (!q.empty()) 46 { 47 int tmp = q.front(); 48 q.pop(); 49 for (int i = 1; i < DEG; ++i) 50 { 51 fa[tmp][i] = fa[fa[tmp][i - 1]][i - 1]; 52 } 53 for (int i = head[tmp]; i != -1; i = edge[i].nxt) 54 { 55 int v = edge[i].to; 56 if (v == fa[tmp][0]) continue; 57 deg[v] = deg[tmp] + 1; 58 fa[v][0] = tmp; 59 q.push(v); 60 } 61 } 62 } 63 64 int LCA(int u, int v) 65 { 66 if (deg[u] > deg[v]) swap(u, v); 67 int hu = deg[u]; 68 int hv = deg[v]; 69 int tu = u, tv = v; 70 for (int det = hv - hu, i = 0; det; det >>= 1, ++i) 71 { 72 if (det & 1) 73 { 74 tv = fa[tv][i]; 75 } 76 } 77 if (tu == tv) return tu; 78 for (int i = DEG - 1; i >= 0; --i) 79 { 80 if (fa[tu][i] == fa[tv][i]) 81 continue; 82 tu = fa[tu][i]; 83 tv = fa[tv][i]; 84 } 85 return fa[tu][0]; 86 } 87 88 int n, m; 89 ll arr[maxn]; 90 91 void DFS(int u, int pre) 92 { 93 for (int i = head[u]; ~i; i = edge[i].nxt) 94 { 95 int v = edge[i].to; 96 if (v == pre) continue; 97 DFS(v, u); 98 arr[u] += arr[v]; 99 } 100 } 101 102 void RUN() 103 { 104 while (~scanf("%d %d", &n, &m)) 105 { 106 init(); 107 memset(arr, 0, sizeof arr); 108 for (int i = 1; i < n; ++i) 109 { 110 int u, v; 111 scanf("%d %d", &u, &v); 112 addedge(u, v); 113 addedge(v, u); 114 } 115 BFS(1); 116 for (int i = 1; i <= m; ++i) 117 { 118 int u, v; 119 scanf("%d %d", &u, &v); 120 arr[u]++; 121 arr[v]++; 122 arr[LCA(u, v)] -= 2; 123 } 124 DFS(1, -1); 125 ll ans = 0; 126 for (int i = 2; i <= n; ++i) 127 { 128 if (!arr[i]) 129 { 130 ans += m; 131 } 132 else if (arr[i] == 1) 133 { 134 ans++; 135 } 136 } 137 printf("%lld\n", ans); 138 } 139 } 140 141 int main() 142 { 143 #ifdef LOCAL_JUDGE 144 freopen("Text.txt", "r", stdin); 145 #endif // LOCAL_JUDGE 146 147 RUN(); 148 149 #ifdef LOCAL_JUDGE 150 fclose(stdin); 151 #endif // LOCAL_JUDGE 152 153 return 0; 154 }
Imperial roads UVALive - 8196
题意:给出一张图,然后询问给出一条边,求有这条边的最小生成树的权值和。
思路:
先求最小生成树,然后询问的边如果在最小生成树里面那么就是原来的最小生成树的权值和。
否则在原来的最小生成树里面的加入一条边,形成个环,然后去掉这个环里面除了加入的边之外的边权最大的边即可。
1 #include<bits/stdc++.h> 2 3 using namespace std; 4 5 typedef long long ll; 6 7 const int maxn = 2e5 + 10; 8 const int DEG = 20; 9 10 int n, m; 11 12 struct node { 13 int u, v; 14 ll w; 15 node() {} 16 node(int u, int v, ll w) :u(u), v(v), w(w) {} 17 inline bool operator < (const node &b)const 18 { 19 return w < b.w; 20 } 21 }; 22 23 struct Edge { 24 int to; 25 int nxt; 26 ll w; 27 Edge() {} 28 Edge(int to, int nxt, ll w) :to(to), nxt(nxt), w(w) {} 29 }edge[maxn << 1]; 30 31 int dis[maxn][DEG]; 32 bool inMST[maxn << 1]; 33 int head[maxn]; 34 int tot; 35 int father[maxn]; 36 vector<node>G; 37 int cnt; 38 map<pair<int, int>, int>mp; 39 40 void addedge(int u, int v, ll w) 41 { 42 edge[tot] = Edge(v, head[u], w); head[u] = tot++; 43 edge[tot] = Edge(u, head[v], w); head[v] = tot++; 44 } 45 46 void Init() 47 { 48 G.clear(); 49 cnt = 0; 50 tot = 0; 51 memset(dis, 0, sizeof dis); 52 memset(head, -1, sizeof head); 53 for (int i = 1; i <= n; ++i) 54 { 55 father[i] = i; 56 } 57 } 58 59 int find(int x) 60 { 61 return x == father[x] ? father[x] : father[x] = find(father[x]); 62 } 63 64 void mix(int x, int y) 65 { 66 x = find(x); 67 y = find(y); 68 if (x != y) 69 { 70 father[x] = y; 71 } 72 } 73 74 bool same(int x, int y) 75 { 76 return find(x) == find(y); 77 } 78 79 ll MST() 80 { 81 mp.clear(); 82 ll res = 0; 83 sort(G.begin(), G.end()); 84 memset(inMST, false, sizeof inMST); 85 for (auto it : G) 86 { 87 int u = it.u; 88 int v = it.v; 89 mp[make_pair(v, u)] = cnt; 90 mp[make_pair(u, v)] = cnt++; 91 } 92 for (auto it : G) 93 { 94 int u = it.u; 95 int v = it.v; 96 if (same(u, v)) continue; 97 mix(u, v); 98 inMST[mp[make_pair(u, v)]] = true; 99 addedge(u, v, it.w); 100 res += it.w; 101 } 102 return res; 103 } 104 105 int fa[maxn][DEG]; 106 int deg[maxn]; 107 108 void BFS(int root) 109 { 110 queue<int>q; 111 deg[root] = 0; 112 fa[root][0] = root; 113 q.push(root); 114 while (!q.empty()) 115 { 116 int tmp = q.front(); 117 q.pop(); 118 for (int i = 1; i < DEG; ++i) 119 { 120 dis[tmp][i] = max(dis[tmp][i - 1], dis[fa[tmp][i - 1]][i - 1]); 121 fa[tmp][i] = fa[fa[tmp][i - 1]][i - 1]; 122 } 123 for (int i = head[tmp]; ~i; i = edge[i].nxt) 124 { 125 int v = edge[i].to; 126 if (v == fa[tmp][0]) continue; 127 deg[v] = deg[tmp] + 1; 128 fa[v][0] = tmp; 129 int id = mp[make_pair(tmp, v)]; 130 dis[v][0] = G[id].w; 131 q.push(v); 132 } 133 } 134 } 135 136 int LCA(int u, int v) 137 { 138 int res = 0; 139 if (deg[u] > deg[v]) 140 swap(u, v); 141 int hu = deg[u], hv = deg[v]; 142 int tu = u, tv = v; 143 for (int det = hv - hu, i = 0; det; det >>= 1, ++i) 144 { 145 if (det & 1) 146 { 147 res = max(res, dis[tv][i]); 148 tv = fa[tv][i]; 149 } 150 } 151 if (tu == tv) return res; 152 for (int i = DEG - 1; i >= 0; --i) 153 { 154 if (fa[tu][i] == fa[tv][i]) continue; 155 res = max(res, max(dis[tu][i], dis[tv][i])); 156 tu = fa[tu][i]; 157 tv = fa[tv][i]; 158 } 159 res = max(res, max(dis[tu][0], dis[tv][0])); 160 return res; 161 } 162 163 void RUN() 164 { 165 while (~scanf("%d %d", &n, &m)) 166 { 167 Init(); 168 for (int i = 1; i <= m; ++i) 169 { 170 int u, v; 171 ll w; 172 scanf("%d %d %lld", &u, &v, &w); 173 G.push_back(node(u, v, w)); 174 } 175 ll ans = MST(); 176 BFS(1); 177 int q; 178 scanf("%d", &q); 179 while (q--) 180 { 181 int u, v; 182 scanf("%d %d", &u, &v); 183 int id = mp[make_pair(u, v)]; 184 ll w = G[id].w; 185 if (inMST[id]) 186 { 187 printf("%lld\n", ans); 188 } 189 else 190 { 191 ll res = LCA(u, v); 192 printf("%lld\n", ans + w - res); 193 } 194 } 195 } 196 } 197 198 int main() 199 { 200 #ifdef LOCAL_JUDGE 201 freopen("Text.txt", "r", stdin); 202 #endif // LOCAL_JUDGE 203 204 RUN(); 205 206 #ifdef LOCAL_JUDGE 207 fclose(stdin); 208 #endif // LOCAL_JUDGE 209 210 return 0; 211 }
CD操作 HDU - 4547
题意:
思路:
从$u-v$的操作数为$dis_u-dis_{LCA{u, v}}$
1 #include<bits/stdc++.h> 2 3 using namespace std; 4 5 typedef long long ll; 6 const int maxn = 1e5 + 10; 7 const int DEG = 20; 8 9 struct Edge { 10 int to, nxt; 11 inline Edge() {} 12 inline Edge(int to, int nxt) :to(to), nxt(nxt) {} 13 }edge[maxn << 1]; 14 15 int head[maxn], tot; 16 17 map<string, int>mp; 18 int dis[maxn]; 19 20 inline void addedge(int u, int v) 21 { 22 edge[tot] = Edge(v, head[u]); 23 head[u] = tot++; 24 } 25 26 inline void init() 27 { 28 memset(head, -1, sizeof head); 29 tot = 0; 30 } 31 32 int fa[maxn][DEG]; 33 int deg[maxn]; 34 35 inline void BFS(int root) 36 { 37 queue<int>q; 38 deg[root] = 0; 39 dis[root] = 0; 40 fa[root][0] = root; 41 q.push(root); 42 while (!q.empty()) 43 { 44 int tmp = q.front(); 45 q.pop(); 46 for (int i = 1; i < DEG; ++i) 47 { 48 fa[tmp][i] = fa[fa[tmp][i - 1]][i - 1]; 49 } 50 for (int i = head[tmp]; i != -1; i = edge[i].nxt) 51 { 52 int v = edge[i].to; 53 if (v == fa[tmp][0]) continue; 54 deg[v] = deg[tmp] + 1; 55 dis[v] = dis[tmp] + 1; 56 fa[v][0] = tmp; 57 q.push(v); 58 } 59 } 60 } 61 62 inline int LCA(int u, int v) 63 { 64 if (deg[u] > deg[v]) swap(u, v); 65 int hu = deg[u]; 66 int hv = deg[v]; 67 int tu = u, tv = v; 68 for (int det = hv - hu, i = 0; det; det >>= 1, ++i) 69 { 70 if (det & 1) 71 { 72 tv = fa[tv][i]; 73 } 74 } 75 if (tu == tv) return tu; 76 for (int i = DEG - 1; i >= 0; --i) 77 { 78 if (fa[tu][i] == fa[tv][i]) 79 continue; 80 tu = fa[tu][i]; 81 tv = fa[tv][i]; 82 } 83 return fa[tu][0]; 84 } 85 86 int n, m; 87 bool flag[maxn]; 88 89 inline void RUN() 90 { 91 int t; 92 cin >> t; 93 while (t--) 94 { 95 cin >> n >> m; 96 init(); 97 mp.clear(); 98 int cnt = 1; 99 memset(flag, false, sizeof flag); 100 for (int i = 1; i < n; ++i) 101 { 102 string s1, s2; 103 cin >> s1 >> s2; 104 if (mp[s1] == 0) 105 { 106 mp[s1] = cnt++; 107 } 108 if (mp[s2] == 0) 109 { 110 mp[s2] = cnt++; 111 } 112 addedge(mp[s2], mp[s1]); 113 addedge(mp[s1], mp[s2]); 114 flag[mp[s1]] = true; 115 } 116 int root = 0; 117 for (int i = 1; i < cnt; ++i) 118 { 119 if (!flag[i]) 120 { 121 root = i; 122 break; 123 } 124 } 125 BFS(root); 126 while (m--) 127 { 128 string s1, s2; 129 cin >> s1 >> s2; 130 int u = mp[s1]; 131 int v = mp[s2]; 132 int tmp = LCA(u, v); 133 int ans = dis[u] - dis[tmp]; 134 if (tmp != v) 135 { 136 ans++; 137 } 138 cout << ans << endl; 139 } 140 } 141 } 142 143 int main() 144 { 145 #ifdef LOCAL_JUDGE 146 freopen("Text.txt", "r", stdin); 147 #endif // LOCAL_JUDGE 148 149 RUN(); 150 151 #ifdef LOCAL_JUDGE 152 fclose(stdin); 153 #endif // LOCAL_JUDGE 154 155 return 0; 156 }
Red Black Tree ZOJ - 4048
题意:有一个树,上面有红点和黑点,有边权,每个点的花费定义为它到离它最近的红点的距离,每次询问给出一些点,能够将这棵树中的一个黑点变为红点,使得这些点中的最大花费最小
思路:
二分答案,符合条件的点不管,将不符合条件的点LCA求出来,变红,然后算距离
ST表求LCA可直接过,复杂度为$O(n \cdot log_n)$。
倍增求LCA复杂度为$O(n \cdot log_n \cdot log_n)$。
倍增求LCA可先根据深度排序,当有两个不符合的点上方的红点不同时则不能通过修改一个点使得所有不符合的点都产生改变,从而剪枝。
ST表。
1 #include <bits/stdc++.h> 2 using namespace std; 3 4 #define N 100010 5 #define ll long long 6 #define INFLL 0x3f3f3f3f3f3f3f3f 7 8 struct Edge 9 { 10 int to, nx; ll w; 11 inline Edge() {} 12 inline Edge(int to, int nx, ll w) : to(to), nx(nx), w(w) {} 13 }edge[N << 1]; 14 15 int t, n, m, q, k; 16 int isred[N], prered[N], head[N], arr[N], pos; 17 int rmq[N << 1], F[N << 1], P[N], deep[N], cnt; 18 ll dist[N]; 19 20 inline void Init() 21 { 22 memset(head, -1, sizeof head); pos = 0; 23 memset(isred, 0, sizeof isred); deep[1] = 0; 24 } 25 26 inline void addedge(int u, int v, ll w) 27 { 28 edge[++pos] = Edge(v, head[u], w); head[u] = pos; 29 } 30 31 struct ST 32 { 33 int mm[N << 1]; 34 int dp[N << 1][20]; 35 inline void init(int n) 36 { 37 mm[0] = -1; 38 for (int i = 1; i <= n; ++i) 39 { 40 mm[i] = ((i & (i - 1)) == 0) ? mm[i - 1] + 1 : mm[i - 1]; 41 dp[i][0] = i; 42 } 43 for (int j = 1; j <= mm[n]; ++j) 44 { 45 for (int i = 1; i + (1 << j) - 1 <= n; ++i) 46 { 47 dp[i][j] = rmq[dp[i][j - 1]] < rmq[dp[i + (1 << (j - 1))][j - 1]] ? dp[i][j - 1] : dp[i + (1 << (j - 1))][j - 1]; 48 } 49 } 50 } 51 inline int query(int a, int b) 52 { 53 if (a > b) swap(a, b); 54 int k = mm[b - a + 1]; 55 return rmq[dp[a][k]] <= rmq[dp[b - (1 << k) + 1][k]] ? dp[a][k] : dp[b - (1 << k) + 1][k]; 56 } 57 }st; 58 59 inline void DFS(int u, int pre, int prer) 60 { 61 F[++cnt] = u; 62 rmq[cnt] = deep[u]; 63 P[u] = cnt; 64 prered[u] = prer; 65 for (int it = head[u]; ~it; it = edge[it].nx) 66 { 67 int v = edge[it].to; 68 if (v == pre) continue; 69 if (isred[v]) dist[v] = 0; 70 else dist[v] = dist[u] + edge[it].w; 71 deep[v] = deep[u] + 1; 72 DFS(v, u, isred[v] ? v : prer); 73 F[++cnt] = u; 74 rmq[cnt] = deep[u]; 75 } 76 } 77 78 inline void Lca_Init(int root, int node_num) 79 { 80 cnt = 0; 81 DFS(root, root, 1); 82 st.init(2 * node_num - 1); 83 } 84 85 inline int query_lca(int u, int v) 86 { 87 return F[st.query(P[u], P[v])]; 88 } 89 90 vector <int> v; 91 inline bool check(ll mid) 92 { 93 v.clear(); 94 for (int i = 1; i <= k; ++i) 95 { 96 if (dist[arr[i]] > mid) 97 v.emplace_back(arr[i]); 98 } 99 if (v.empty()) return true; 100 int lca = v[0]; 101 for (int i = 1, len = v.size(); i < len; ++i) 102 lca = query_lca(lca, v[i]); 103 if (isred[lca]) return false; 104 for (auto it : v) 105 { 106 if (deep[lca] < deep[prered[it]]) return false; 107 else if (dist[it] - dist[lca] > mid) return false; 108 } 109 return true; 110 } 111 112 inline void Run() 113 { 114 for (scanf("%d", &t); t--; ) 115 { 116 scanf("%d%d%d", &n, &m, &q); Init(); 117 for (int i = 1, u; i <= m; ++i) 118 { 119 scanf("%d", &u); 120 isred[u] = 1; 121 } 122 ll w; 123 for (int i = 1, u, v; i < n; ++i) 124 { 125 scanf("%d%d%lld", &u, &v, &w); 126 addedge(u, v, w); addedge(v, u, w); 127 } 128 Lca_Init(1, n); 129 for (int qq = 1; qq <= q; ++qq) 130 { 131 scanf("%d", &k); 132 for (int i = 1; i <= k; ++i) scanf("%d", arr + i); 133 if (k == 1) 134 { 135 puts("0"); 136 continue; 137 } 138 ll l = 0, r = INFLL, ans; 139 while (r - l >= 0) 140 { 141 ll mid = (l + r) >> 1; 142 if (check(mid)) 143 { 144 ans = mid; 145 r = mid - 1; 146 } 147 else 148 l = mid + 1; 149 } 150 printf("%lld\n", ans); 151 } 152 } 153 } 154 155 int main() 156 { 157 #ifdef LOCAL 158 freopen("Test.in", "r", stdin); 159 #endif 160 161 Run(); 162 return 0; 163 }
倍增求LCA。
1 #include<bits/stdc++.h> 2 3 using namespace std; 4 5 typedef long long ll; 6 7 const int INF = 0x3f3f3f3f; 8 const ll INFLL = 0x3f3f3f3f3f3f3f3f; 9 const ll MOD = (int)1e9 + 7; 10 const int maxn = (int)1e5 + 10; 11 12 const int DEG = 20; 13 14 struct Edge { 15 int to, nxt; 16 ll w; 17 Edge() {} 18 Edge(int to, int nxt, ll w) :to(to), nxt(nxt), w(w) {} 19 }edge[maxn << 1]; 20 21 int head[maxn], tot; 22 int red[maxn]; 23 24 void addedge(int u, int v, ll w) 25 { 26 edge[tot] = Edge(v, head[u], w); head[u] = tot++; 27 } 28 29 void Init(int n) 30 { 31 for (int i = 1; i <= n; ++i) 32 { 33 red[i] = 0; 34 head[i] = -1; 35 } 36 tot = 0; 37 } 38 39 ll dis[maxn]; 40 int fa[maxn][DEG]; 41 int deg[maxn]; 42 int pre[maxn]; 43 44 void BFS(int root) 45 { 46 queue<int>q; 47 dis[root] = 0; 48 deg[root] = 0; 49 fa[root][0] = root; 50 pre[root] = root; 51 q.push(root); 52 while (!q.empty()) 53 { 54 int tmp = q.front(); 55 q.pop(); 56 for (int i = 1; i < DEG; ++i) 57 { 58 fa[tmp][i] = fa[fa[tmp][i - 1]][i - 1]; 59 } 60 for (int i = head[tmp]; ~i; i = edge[i].nxt) 61 { 62 int v = edge[i].to; 63 ll w = edge[i].w; 64 if (v == fa[tmp][0]) continue; 65 deg[v] = deg[tmp] + 1; 66 fa[v][0] = tmp; 67 if (red[v]) 68 { 69 pre[v] = v; 70 } 71 else 72 { 73 pre[v] = pre[tmp]; 74 } 75 if (red[v]) 76 { 77 dis[v] = 0; 78 } 79 else 80 { 81 dis[v] = dis[tmp] + w; 82 } 83 q.push(v); 84 } 85 } 86 } 87 88 int LCA(int u, int v) 89 { 90 if (deg[u] > deg[v]) swap(u, v); 91 int hu = deg[u], hv = deg[v]; 92 int tu = u, tv = v; 93 for (int det = hv - hu, i = 0; det; det >>= 1, ++i) 94 { 95 if (det & 1) 96 { 97 tv = fa[tv][i]; 98 } 99 } 100 if (tu == tv) return tu; 101 for (int i = DEG - 1; i >= 0; --i) 102 { 103 if (fa[tu][i] == fa[tv][i]) continue; 104 tu = fa[tu][i], tv = fa[tv][i]; 105 } 106 return fa[tu][0]; 107 } 108 109 int n, m, q, k; 110 int arr[maxn]; 111 112 bool cmp(int a, int b) 113 { 114 return dis[a] > dis[b]; 115 } 116 117 bool check(ll mid) 118 { 119 int root = arr[1]; 120 int cnt = 0; 121 for (int i = 1; i <= k; ++i) 122 { 123 if (dis[arr[i]] > mid) 124 { 125 if (pre[root] != pre[arr[i]]) return false; 126 root = LCA(root, arr[i]); 127 cnt++; 128 } 129 } 130 if (cnt == 1 || cnt == 0) return true; 131 for (int i = 1; i <= k; ++i) 132 { 133 if (dis[arr[i]] > mid) 134 { 135 if (dis[arr[i]] - dis[root] > mid) return false; 136 } 137 } 138 return true; 139 } 140 141 void RUN() 142 { 143 int t; 144 scanf("%d", &t); 145 while (t--) 146 { 147 scanf("%d %d %d", &n, &m, &q); 148 Init(n); 149 for (int i = 1; i <= m; ++i) 150 { 151 int u; 152 scanf("%d", &u); 153 red[u] = 1; 154 } 155 for (int i = 1; i < n; ++i) 156 { 157 int u, v; 158 ll w; 159 scanf("%d %d %lld", &u, &v, &w); 160 addedge(u, v, w); 161 addedge(v, u, w); 162 } 163 BFS(1); 164 while (q--) 165 { 166 scanf("%d", &k); 167 for (int i = 1; i <= k; ++i) 168 { 169 scanf("%d", arr + i); 170 } 171 if (k == 1) 172 { 173 puts("0"); 174 continue; 175 } 176 sort(arr + 1, arr + 1 + k, cmp); 177 ll l = 0; 178 ll r = INFLL; 179 ll ans = 0; 180 while (r - l >= 0) 181 { 182 ll mid = (r + l) >> 1; 183 if (check(mid)) 184 { 185 r = mid - 1; 186 ans = mid; 187 } 188 else 189 { 190 l = mid + 1; 191 } 192 } 193 printf("%lld\n", ans); 194 } 195 } 196 } 197 198 int main() 199 { 200 #ifdef LOCAL_JUDGE 201 freopen("Text.txt", "r", stdin); 202 #endif // LOCAL_JUDGE 203 204 RUN(); 205 206 #ifdef LOCAL_JUDGE 207 fclose(stdin); 208 #endif // LOCAL_JUDGE 209 return 0; 210 }