hdu 4008 Parent and son
来源:互联网 发布:软件中的引擎 编辑:程序博客网 时间:2024/05/16 11:03
/*首先以1为根,扫描一遍树,得到每个节点的minchild[i][2],儿子节点的最小值和次小值(不同子树的)和每个节点的最小后缀的值mindown[i](1)如果x是y的父节点的话,那么直接输出mindown[i],minchild[i][0]即可(2)如果y是x的父节点【1】当y不为1的时候 对于第一问 找到y到x这条路径上离y最近的节点z,若z=minchild[0],输出minchild[1]和y的父亲节点的最小值, 否则输出minchild[0]和y的父亲节点的最小值 对于第二问 输出1【2】当y是1的时候(预先处理出他的最小和次小的后缀值mindown[0],mindown[1]) 对于第一问 找到y到x这条路径上离y最近的节点z,若z=minchild[0],输出minchild[1],否则输出minchild[0] 对于第二问 找到y到x这条路径上离y最近的节点z的最小后缀值(包括z),和mindown[0]比较, 不同输出mindown[1],否则输出mindown[0]*/#include <cstdio>#include <cstring>#include <algorithm>using namespace std;const int MAXN = 100000 + 1234;struct EDGE{ int u, v;} edge[MAXN * 2];int cnt;int minchild[MAXN][2];int mindown[MAXN];int fa[MAXN][20];int head[MAXN];int n;int depth[MAXN], maxdepth, topk;bool cmp(EDGE a, EDGE b){ if(a. u != b.u) return a.u < b.u; return a.v < b.v;}void insert(int *s, int x){ if(x < s[0]) { s[1] = s[0]; s[0] = x; } else if(x < s[1]) s[1] = x;}void dfs(int root){ minchild[root][0] = minchild[root][1] = mindown[root] = n + 1;//赋为最大值 for(int p = head[root]; p < cnt && edge[p].u == root; p++) { int v = edge[p].v; if(v == fa[root][0]) continue;//访问到了父节点 fa[v][0] = root; insert(minchild[root], v); depth[v] = depth[root] + 1; dfs(v); mindown[root] = min(mindown[root], mindown[v]); } maxdepth = max(maxdepth, depth[root]); mindown[root] = min(mindown[root], minchild[root][0]);}int findfather(int x, int step){ int k = topk - 1; while(step > 0) { while((1 << k) > step) k--; x = fa[x][k]; step -= (1 << k); } return x;}int main(){ int T; int q, x, y; scanf("%d", &T); while(T--) { scanf("%d%d", &n, &q); cnt = n - 1; for(int i = 0; i < cnt; i++) { scanf("%d%d", &edge[i].u, &edge[i].v); edge[i + cnt].u = edge[i].v; edge[i + cnt].v = edge[i].u; } cnt = cnt + cnt; sort(edge, edge + cnt, cmp); head[1] = 0; for(int i = 1; i < cnt; i++) if(edge[i].u != edge[i-1].u) head[edge[i].u] = i; fa[1][0] = 0; depth[1] = maxdepth = 0; dfs(1); topk = 0; while((1 << topk) <= maxdepth) topk++; for(int k = 1; k < topk; k++) for(int i = 1; i <= n; i++) if(fa[i][k - 1] != 0) fa[i][k] = fa[fa[i][k-1]][k-1]; int mindown1[2]; mindown1[0] = mindown1[1] = n + 1; for(int p = head[1]; p < cnt && edge[p].u == 1; p++) { int v = edge[p].v; int rv = min(mindown[v], v); insert(mindown1, rv); } while(q--) { scanf("%d%d", &x, &y);//不会出现x==y的情况 int ans1 = n + 1, ans2 =n + 1; if(y == 1) { int z = findfather(x, depth[x] - depth[y] - 1); int rz = min(z, mindown[z]); ans1 = (z == minchild[1][0] ? minchild[1][1] : minchild[1][0]); ans2 = (rz == mindown1[0] ? mindown1[1] : mindown1[0]); } else { bool flag = false; int z; if(depth[y] < depth[x]) { z = findfather(x, depth[x] - depth[y] - 1); if(fa[z][0] == y) flag = true; } if(flag) { //printf("z = %d\n", z); //printf("fa=%d\n", fa[y][0]); ans1 = (z == minchild[y][0] ? min(minchild[y][1], fa[y][0]) : min(minchild[y][0], fa[y][0])); ans2 = 1; } else { ans1 = minchild[y][0]; ans2 = mindown[y]; } } if (ans1 > n) printf("no answers!\n"); else printf("%d %d\n", ans1, ans2); } puts(""); } return 0;}