首页 > 代码库 > HDU 4916 Count on the path

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