HDU 4916 Count on the path

意甲冠军:

考虑到一棵树,m询价  不要求回答每一次询价u和v通过在两个节点形成的最低等级点路径

思路:

一開始以为是LCA…  只是T了好几次…  后来发现不用LCA也可做

考虑每一个询问u和v  假设他们的lca不是1  则1一定是答案  只是求lca会T  那么我们仅仅须要在遍历树的时候给节点染色  染的颜色就是1的儿子的颜色  假设x这个点在y的子树中(y是1的儿子)那么他的颜色就是y

染完色后我们考虑答案是怎样构成的


如图所看到的  答案即是  红色  蓝色  绿色的子树中节点的最小值  那么我们仅仅须要分开三部分求解就可以

定义f[u][x]表示以u为根的子树中第x大的节点标号  这个能够通过树形dp求解  有了这个就能够解决绿色和红色的部分

定义g[u]表示u节点上面到1的路径中旁側的子树的最小节点标号  即图中蓝色部分  也能够利用f做树形dp求解


注意:

题目中不让蓝色部分包括绿色部分  也不把绿色部分放在红色部分中考虑的原因就是u和v节点中的一个可能是1

因为我写的是dfs  杭电会爆栈  所以记得加栈  并用C++提交


代码:

#pragma comment(linker, "/STACK:102400000,102400000")
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define N 1000010

int f[N][4], g[N], col[N], head[N];
int n, m, color, tot, ans;
struct edge {
    int v, next;
} ed[N * 2];

int d(int a, int b) {
    if (a < b)
        return a;
    return b;
}

void add(int u, int v) {
    ed[tot].v = v;
    ed[tot].next = head[u];
    head[u] = tot++;
}

void dfs1(int u, int fa) {
    int i, v;
    if (u != 1)
        col[u] = color;
    for (i = head[u]; ~i; i = ed[i].next) {
        v = ed[i].v;
        if (u == 1)
            color = v;
        if (v != fa) {
            dfs1(v, u);
            f[u][3] = d(v, f[v][0]);
            sort(f[u], f[u] + 4);
        }
    }
}

void dfs2(int u, int fa) {
    if (fa != 1) {
        if (d(u, f[u][0]) != f[fa][0])
            g[u] = f[fa][0];
        else
            g[u] = f[fa][1];
        if (g[u] > g[fa])
            g[u] = g[fa];
    }
    int i, v;
    for (i = head[u]; ~i; i = ed[i].next) {
        v = ed[i].v;
        if (v != fa)
            dfs2(v, u);
    }
}

int main() {
    int i, j, u, v;
    while (~scanf("%d%d", &n, &m)) {
        for (i = 1; i <= n; i++) {
            f[i][0] = f[i][1] = f[i][2] = f[i][3] = g[i] = N;
            head[i] = -1;
        }
        col[1] = 1;
        tot = ans = 0;
        for (i = 1; i < n; i++) {
            scanf("%d%d", &u, &v);
            add(u, v);
            add(v, u);
        }
        dfs1(1, 1);
        dfs2(1, 1);
        for (i = 1; i <= m; i++) {
            scanf("%d%d", &u, &v);
            u ^= ans;
            v ^= ans;
            if (col[u] == col[v]) {
                if (u == 1 || v == 1)
                    ans = 2;
                else
                    ans = 1;
            } else {
                if (u > v)
                    swap(u, v);
                ans = min(f[v][0], min(g[u], g[v]));
                if (u != 1) {
                    ans = min(ans, f[u][0]);
                    v = min(col[v], f[col[v]][0]);
                    u = min(col[u], f[col[u]][0]);
                    for (j = 0; j < 3; j++) {
                        if (f[1][j] != u && f[1][j] != v) {
                            ans = min(ans, f[1][j]);
                            break;
                        }
                    }
                } else {
                    v = min(col[v], f[col[v]][0]);
                    for (j = 0; j < 3; j++) {
                        if (f[1][j] != v) {
                            ans = min(ans, f[1][j]);
                            break;
                        }
                    }
                }
            }
            printf("%d\n", ans);
        }
    }
    return 0;
}


版权声明:本文博主原创文章,博客,未经同意不得转载。

posted @ 2015-09-15 09:44  zfyouxi  阅读(164)  评论(0编辑  收藏  举报