[题解]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 }
distance (Tarjan)
  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 }
distance (st table)

  话说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算法求森林最短路)

ST——LCA在线算法

POJ1679 The Unique MST 题解 次小生成树 题解 Kruskal+暴力LCA解法(因为倍增不会写)

算法复习——分块算法