题目链接:http://acm.nbut.edu.cn/problem/view.xhtml?id=1554
题意:给出一个n((nleq 10000))个节点的树,然后给出m((mleq100000))个询问,每个询问给出两个节点x和y,问从x到y的路径是否经过与x深度相同的节点?
分析:
用depth[k]表示标号为k的节点在树中的深度
(1) 如果depth[x]>depth[y],显然不经过;如果depth[x]==depth[y],显然经过;如果depth[x]<depth[y],如果x是y的祖先节点,则不经过否则经过;
(2) 根据(1),可以先计算出每个节点的深度,就能通过比较深度搞定询问中的前两种情况。对于depth[x]<depth[y],需要判断x是否为y的祖先
(3) 这里不需要求出x,y的lca,只需要判断depth[x]<depth[y]时、x是否为y的祖先即可,显然dfs就可以做到,如果则x是y的祖先,那么dfs遍历到y时,x应该在栈中。
(4) 可以离线操作:将询问中节点y对应的所有x放入y的队列中,当遍历到y时,直接判断x是否在栈中即可
(5) 标程采用了另一中做法:按照dfs遍历的顺序维护一个标号flag,dfs时记录每个节点的标号范围,即进入一个节点x时l[x]=falg++,出x时r[x]=flag++,那么[ l[x], r[x] ]就是x的子孙的标号范围,这样通过比较范围可以确定x是否为y的祖先。
题目给出的节点是字符串类型的,用map映射到int型
1 # include <cstdio> 2 # include <cstring> 3 # include <map> 4 # include <vector> 5 # include <string> 6 using namespace std; 7 8 const int maxn = 10005; 9 10 int n, m; 11 map <string, int> mp; 12 int root; 13 vector <int> G[maxn]; 14 vector <int> Q[maxn]; 15 int d[maxn]; 16 17 char x[15], y[15]; 18 string sx, sy; 19 20 int id; 21 int ans; 22 23 bool ins[maxn]; 24 void dfs_solve(int cur) 25 { 26 ins[cur] = true; 27 for (int i = 0; i < Q[cur].size(); ++i) { 28 if (ins[ Q[cur][i] ] == false) ++ans; 29 } 30 for (int i = 0; i < G[cur].size(); ++i) dfs_solve(G[cur][i]); 31 ins[cur] = false; 32 } 33 void dfs_depth(int cur, int depth) 34 { 35 d[cur] = depth; 36 for (int i = 0; i < G[cur].size(); ++i) dfs_depth(G[cur][i], depth+1); 37 } 38 int add(const string &s) 39 { 40 int ret = mp[s]; 41 if (ret < 1) ret = (mp[s] = ++id); 42 return ret; 43 } 44 45 int main() 46 { 47 while (EOF != scanf("%d%d", &n, &m)) { 48 mp.clear(); 49 for (int i = 1; i <= n+1; ++i) G[i].clear(); 50 id = 0; 51 for (int i = 0; i < n; ++i) { 52 scanf("%s%s", x, y); 53 sx = x, sy = y; 54 int ix = add(sx); 55 int iy = add(sy); 56 if (strcmp(y, "Hungar") == 0) root = iy; 57 G[iy].push_back(ix); 58 } 59 for (int i = 1; i <= id; ++i) d[i] = 0; 60 dfs_depth(root, 0); 61 ans = 0; 62 for (int i = 1; i <= id; ++i) Q[i].clear(); 63 for (int i = 0; i < m; ++i) { 64 scanf("%s%s", x, y); 65 sx = x, sy = y; 66 int ix = mp[sx]; 67 int iy = mp[sy]; 68 if (d[ix] < d[iy]) Q[iy].push_back(ix); 69 else if (d[ix] == d[iy]) ++ans; 70 } 71 for (int i = 1; i <= id; ++i) ins[i] = false; 72 dfs_solve(root); 73 printf("%d ", ans); 74 } 75 76 return 0; 77 }
1 # include <cstdio> 2 # include <cstring> 3 # include <string> 4 # include <map> 5 # include <vector> 6 using namespace std; 7 8 const int maxn = 10005; 9 10 int n, m; 11 map <string, int> mp; 12 vector <int> G[maxn]; 13 int d[maxn]; 14 int l[maxn], r[maxn]; 15 int id, root; 16 char sx[15], sy[15]; 17 string stx, sty; 18 int cnt; 19 void dfs(int cur, int depth) 20 { 21 d[cur] = depth; 22 l[cur] = cnt++; 23 for (int i = 0; i < G[cur].size(); ++i) dfs(G[cur][i], depth+1); 24 r[cur] = cnt++; 25 } 26 27 int add(const string &s) 28 { 29 return mp[s]>0 ? mp[s]:(mp[s]=++id); 30 } 31 32 void init(void) 33 { 34 id = 0; 35 mp.clear(); 36 for (int i = 1; i <= n+1; ++i) G[i].clear(); 37 for (int i = 0; i < n; ++i) { 38 scanf("%s%s", sx, sy); stx = sx, sty = sy; 39 int x = add(stx), y = add(sty); 40 if (strcmp(sy, "Hungar") == 0) root = y; 41 G[y].push_back(x); 42 } 43 cnt = 0; 44 dfs(root, 0); 45 } 46 47 void solve(void) 48 { 49 int ans = 0; 50 for (int i = 0; i < m; ++i) { 51 scanf("%s%s", sx, sy); 52 stx = sx, sty = sy; 53 int x = mp[stx]; 54 int y = mp[sty]; 55 if ((d[x]<d[y] && !(l[x]<l[y] && r[y]<r[x])) || (d[x]==d[y])) ++ans; 56 } 57 printf("%d ", ans); 58 } 59 60 int main() 61 { 62 while (EOF != scanf("%d%d", &n, &m)) { 63 init(); 64 solve(); 65 } 66 return 0; 67 }