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;}


原创粉丝点击