意甲冠军:
考虑到一棵树,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 ", ans); } } return 0; }
版权声明:本文博主原创文章,博客,未经同意不得转载。