[题解]LCA练习+部分算法复习 2017.1.22
Posted 阿波罗2003
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[题解]LCA练习+部分算法复习 2017.1.22相关的知识,希望对你有一定的参考价值。
第一题就LCA即可。不过推荐用Tarjan(最快,常数很小)。然后Tarjan的时候顺便就出一个dist[i],表示i节点到根节点的距离。求出了LCA,那么两点间的距离就为dist[u] + dist[v] - 2 * dist[lca]。
Code
1 #include<iostream> 2 #include<sstream> 3 #include<cstdio> 4 #include<cmath> 5 #include<cstdlib> 6 #include<cstring> 7 #include<cctype> 8 #include<queue> 9 #include<set> 10 #include<map> 11 #include<stack> 12 #include<vector> 13 #include<algorithm> 14 #ifndef WIN32 15 #define AUTO "%I64d" 16 #else 17 #define AUTO "%lld" 18 #endif 19 using namespace std; 20 typedef bool boolean; 21 #define smin(a, b) (a) = min((a), (b)) 22 #define smax(a, b) (a) = max((a), (b)) 23 template<typename T> 24 inline void readInteger(T& u){ 25 char x; 26 int aFlag = 1; 27 while(!isdigit((x = getchar())) && x != \'-\'); 28 if(x == \'-\'){ 29 aFlag = -1; 30 x = getchar(); 31 } 32 for(u = x - \'0\'; isdigit((x = getchar())); u = u * 10 + x - \'0\'); 33 ungetc(x, stdin); 34 u *= aFlag; 35 } 36 37 typedef class Edge { 38 public: 39 int end; 40 int next; 41 int w; 42 Edge(const int end = 0, const int next = 0, const int w = 0):end(end), next(next), w(w){ } 43 }Edge; 44 45 typedef class MapManager{ 46 public: 47 int ce; 48 Edge* edges; 49 int* h; 50 MapManager():ce(0), edges(NULL), h(NULL){ } 51 MapManager(int points, int limit):ce(0){ 52 edges = new Edge[(const int)(limit + 1)]; 53 h = new int[(const int)(points + 1)]; 54 memset(h, 0, sizeof(int) * (points + 1)); 55 } 56 inline void addEdge(int from, int end, int w){ 57 edges[++ce] = Edge(end, h[from], w); 58 h[from] = ce; 59 } 60 inline void addDoubleEdge(int from, int end, int w){ 61 addEdge(from, end, w); 62 addEdge(end, from, w); 63 } 64 Edge& operator [](int pos){ 65 return edges[pos]; 66 } 67 }MapManager; 68 #define m_begin(g, i) (g).h[(i)] 69 70 typedef class union_found{ 71 public: 72 int *f; 73 union_found():f(NULL) {} 74 union_found(int points) { 75 f = new int[(const int)(points + 1)]; 76 } 77 int find(int x) { 78 if(f[x] != x) return f[x] = find(f[x]); 79 return f[x]; 80 } 81 void unit(int fa, int so) { 82 int ffa = find(fa); 83 int fso = find(so); 84 f[fso] = ffa; 85 } 86 int& operator [](int pos){ 87 return f[pos]; 88 } 89 }union_found; 90 91 int n, m; 92 MapManager g; 93 MapManager q; 94 int *results; 95 boolean* enable; 96 int *querya, *queryb; 97 union_found uf; 98 boolean* visited; 99 int* dist; 100 101 inline void init(){ 102 readInteger(n); 103 g = MapManager(n, 2 * n); 104 for(int i = 1, a, b, c; i < n; i++){ 105 readInteger(a); 106 readInteger(b); 107 readInteger(c); 108 g.addDoubleEdge(a, b, c); 109 } 110 readInteger(m); 111 q = MapManager(n, 2 * m); 112 querya = new int[(const int)(m + 1)]; 113 queryb = new int[(const int)(m + 1)]; 114 results = new int[(const int)(m + 1)]; 115 enable = new boolean[(const int)(m + 1)]; 116 dist = new int[(const int)(n + 1)]; 117 uf = union_found(n); 118 visited = new boolean[(const int)(n + 1)]; 119 memset(visited, false, sizeof(boolean) * (n + 1)); 120 memset(enable, true, sizeof(boolean) * (m + 1)); 121 for(int i = 1; i <= m; i++){ 122 readInteger(querya[i]); 123 readInteger(queryb[i]); 124 q.addDoubleEdge(querya[i], queryb[i], i); 125 } 126 dist[1] = 0; 127 } 128 129 void tarjan(int node, int f){ 130 uf[node] = node; 131 visited[node] = true; 132 for(int i = m_begin(g, node); i != 0; i = g[i].next){ 133 int& e = g[i].end; 134 if(e == f) continue; 135 dist[e] = dist[node] + g[i].w; 136 tarjan(e, node); 137 uf[e] = node; 138 } 139 for(int i = m_begin(q, node); i != 0; i = q[i].next) { 140 int& e = q[i].end; 141 if(visited[e] && enable[q[i].w]){ 142 int lca = uf.find(e); 143 results[q[i].w] = lca; 144 enable[q[i].w] = false; 145 } 146 } 147 } 148 149 inline void solve(){ 150 tarjan(1, 0); 151 for(int i = 1; i <= m; i++){ 152 int dis = dist[querya[i]] + dist[queryb[i]] - 2 * dist[results[i]]; 153 printf("%d\\n", dis); 154 } 155 } 156 157 int main(){ 158 freopen("distance.in", "r", stdin); 159 freopen("distance.out", "w", stdout); 160 init(); 161 solve(); 162 return 0; 163 }
1 #include<iostream> 2 #include<sstream> 3 #include<cstdio> 4 #include<cmath> 5 #include<cstdlib> 6 #include<cstring> 7 #include<cctype> 8 #include<queue> 9 #include<set> 10 #include<map> 11 #include<stack> 12 #include<vector> 13 #include<algorithm> 14 #ifndef WIN32 15 #define AUTO "%I64d" 16 #else 17 #define AUTO "%lld" 18 #endif 19 using namespace std; 20 typedef bool boolean; 21 #define smin(a, b) (a) = min((a), (b)) 22 #define smax(a, b) (a) = max((a), (b)) 23 template<typename T> 24 inline void readInteger(T& u){ 25 char x; 26 int aFlag = 1; 27 while(!isdigit((x = getchar())) && x != \'-\'); 28 if(x == \'-\'){ 29 aFlag = -1; 30 x = getchar(); 31 } 32 for(u = x - \'0\'; isdigit((x = getchar())); u = u * 10 + x - \'0\'); 33 ungetc(x, stdin); 34 u *= aFlag; 35 } 36 37 template<typename T>class Matrix{ 38 public: 39 T *p; 40 int lines; 41 int rows; 42 Matrix():p(NULL){ } 43 Matrix(int rows, int lines):lines(lines), rows(rows){ 44 p = new T[(lines * rows)]; 45 } 46 T* operator [](int pos){ 47 return (p + pos * lines); 48 } 49 }; 50 #define matset(m, i, s) memset((m).p, (i), (s) * (m).lines * (m).rows) 51 52 ///map template starts 53 typedef class Edge{ 54 public: 55 int end; 56 int next; 57 int w; 58 Edge(const int end = 0, const int next = 0, const int w = 0):end(end), next(next), w(w){} 59 }Edge; 60 typedef class MapManager{ 61 public: 62 int ce; 63 int *h; 64 int w; 65 Edge *edge; 66 MapManager(){} 67 MapManager(int points, int limit):ce(0){ 68 h = new int[(const int)(points + 1)]; 69 edge = new Edge[(const int)(limit + 1)]; 70 memset(h, 0, sizeof(int) * (points + 1)); 71 } 72 inline void addEdge(int from, int end, int w){ 73 edge[++ce] = Edge(end, h[from], w); 74 h[from] = ce; 75 } 76 inline void addDoubleEdge(int from, int end, int w){ 77 addEdge(from, end, w); 78 addEdge(end, from, w); 79 } 80 Edge& operator[] (int pos) { 81 return edge[pos]; 82 } 83 }MapManager; 84 #define m_begin(g, i) (g).h[(i)] 85 ///map template ends 86 87 int n, m; 88 int cnt = 0; 89 Matrix<int> st; 90 int* seq; 91 int* dep; 92 int *app; 93 MapManager g; 94 int *mlog2; 95 long long *dist; 96 97 inline void init() { 98 readInteger(n); 99 g = MapManager(n, 2 * n); 100 seq = new int[(const int)(2 * n + 1)]; 101 dist = new long long[(const int)(n + 1)]; 102 dep = new int[(const int)(n + 1)]; 103 app = new int[(const int)(n + 1)]; 104 for(int i = 1, a, b, w; i < n; i++){ 105 readInteger(a); 106 readInteger(b); 107 readInteger(w); 108 g.addDoubleEdge(a, b, w); 109 } 110 dist[1] = 0; 111 dep[0] = 0; 112 } 113 114 void dfs(int node, int f) { 115 seq[++cnt] = node; 116 app[node] = cnt; 117 dep[node] = dep[f] + 1; 118 for(int i = m_begin(g, node); i != 0; i = g[i].next) { 119 int& e = g[i].end; 120 if(e == f) continue; 121 dist[e] = dist[node] + g[i].w; 122 dfs(e, node); 123 seq[++cnt] = node; 124 } 125 } 126 127 inline void init_log() { 128 mlog2 = new int[(const int)(2 * n + 1)]; 129 mlog2[1] = 0; 130 for(int i = 2; i <= 2 * n; i++) 131 mlog2[i] = mlog2[i / 2] + 1; 132 } 133 134 inline void init_st() { 135 init_log(); 136 st = Matrix<int>(cnt, mlog2[cnt] + 1); 137 for(int i = 1; i <= cnt; i++) 138 st[i][0] = seq[i]; 139 for(int j = 1; j <= mlog2[cnt]; j++) 140 for(int i = 1; i + (1 << j) - 1 <= cnt; i++) 141 st[i][j] = (dep[st[i][j - 1]] < dep[st[i + (1 << (j - 1))][j - 1]]) ? (st[i][j - 1]) : (st[i + (1 << (j - 1))][j - 1]); 142 } 143 144 inline int lca(int a, int b) { 145 if(app[a] > app[b]) swap(a, b); 146 int pos = mlog2[app[b] - app[a] + 1]; 147 int u = st[app[a]][pos]; 148 int v = st[app[b] - (1 << pos) + 1][pos]; 149 return (dep[u] > dep[v]) ? (v) : (u); 150 } 151 152 long long dis; 153 inline void solve() { 154 readInteger(m); 155 for(int i = 1, a, b; i <= m; i++){ 156 readInteger(a); 157 readInteger(b); 158 int l = lca(a, b); 159 dis = dist[a] + dist[b] - 2 * dist[l]; 160 printf(AUTO"\\n", dis); 161 } 162 } 163 164 int main() { 165 freopen("distance.in", "r", stdin); 166 freopen("distance.out", "w", stdout); 167 init(); 168 dfs(1, 0); 169 init_st(); 170 solve(); 171 return 0; 172 }
话说ST表在n,q都尽量大的情况下,其他数据随机,竟然平均一个点比Tarjan 0.05s左右。(也有可能是我的st表写得比较丑)
第二题还是一遍dfs序,接着可以开开心心地放线段树去装逼了。(然而我把某些"+="写成了"=",于是AK又没有了。。一定是写这道题和检查的时候头脑都不清醒)
Code
1 #include<iostream> 2 #include<sstream> 3 #include<cstdio> 4 #include<cmath> 5 #include<cstdlib> 6 #include<cstring> 7 #include<cctype> 8 #include<queue> 9 #include<set> 10 #include<map> 11 #include<stack> 12 #include<vector> 13 #include<algorithm> 14 #ifdef WIN32 15 #define AUTO "%I64d" 16 #else 17 #define AUTO "%lld" 18 #endif 19 using namespace std; 20 typedef bool boolean; 21 #define smin(a, b) (a) = min((a), (b)) 22 #define smax(a, b) (a) = max((a), (b)) 23 template<typename T> 24 inline void readInteger(T& u){ 25 char x; 26 int aFlag = 1; 27 while(!isdigit((x = getchar())) && x != \'-\'); 28 if(x == \'-\'){ 29 aFlag = -1; 30 x = getchar(); 31 } 32 for(u = x - \'0\'; isdigit((x = getchar())); u = u * 10 + x - \'0\'); 33 ungetc(x, stdin); 34 u *=以上是关于[题解]LCA练习+部分算法复习 2017.1.22的主要内容,如果未能解决你的问题,请参考以下文章牛客网_2018年全国多校算法寒假训练营练习比赛(第一场)_部分题解
BZOJ 3626: [LNOI2014]LCA 树链剖分 线段树 离线
HDU2874 Connections between cities(并查集+倍增LCA算法求森林最短路)