标签:
唔 已经有一个多月没有写题解了, 其实这一个多月也是做了一些题目的,但是就是比较懒啊,所以都堆在一起没有写了~~。
题目链接: http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=26842
题意: 给出一棵树(有默认根), 每个节点有一个权值,再给出q个询问,每个询问包含v k两个变量, 让你输出树根和v节点的路径上,权值大于等于k的离树根最近的节点。
思路: 算是倍增法 + dp的入门练习吧.
dp[v][i] 表示节点v ~ 它的2^i号祖先的路径上点权的最大值
fa[v][i] 表示节点v 的第2^i 号祖先
转移的时候就是 dp[v][i] = max(dp[v][i - 1], dp[fa[v][i-1]][i-1]) ,其转移的思路大致就是将v ~ 2^i的路径分成两段,
一段是v ~ 2^(i-1) 一段是2^(i-1) ~2^i
在处理询问的时候用的是类似二分的思想, 如果v的第2^i号祖先满足条件,我就把v节点变成2^i号祖先,否则把i--。
code:
#include <cstdio> #include <iostream> #include <algorithm> #include <cstring> #include <vector> #define clr(x, y) memset(x, y, sizeof x) #define inf 1000000000 using namespace std; const int maxn = 100005; const int maxp = 18; typedef long long LL; vector<int> G[maxn]; int fa[maxn][maxp]; int dp[maxn][maxp]; int val[maxn]; int n, q; void dfs(int u) { int sz = G[u].size(); for (int i = 0; i < sz; i++) { int v = G[u][i]; fa[v][0] = u; dp[v][0] = val[v]; //--* v ~ u的路径上不包括u for (int j = 1; j < maxp; j++) fa[v][j] = fa[fa[v][j-1]][j-1]; for (int j = 1; j < maxp; j++) dp[v][j] = max(dp[v][j-1], dp[fa[v][j-1]][j-1]); dfs(v); } } int solve(int a, int b) { for (int i = maxp - 1; i >= 0; i--) { if (dp[fa[a][i]][i] >= b) a = fa[a][i]; } return a; } int main() { int T; int a, b, ff; scanf("%d", &T); for (int kk = 1; kk <= T; kk++) { scanf("%d%d", &n, &q); for (int i = 0; i <= n; i++) G[i].clear(); val[0] = 1; for (int i = 0; i < maxp; i++) { dp[0][i] = val[0]; fa[0][i] = 0; } for (int i = 1; i < n; i++) { scanf("%d%d", &ff, &val[i]); G[ff].push_back(i); } dfs(0); printf("Case %d:\n",kk); while(q--) { scanf("%d%d", &a, &b); printf("%d\n", solve(a, b)); } } return 0; }
标签:
原文地址:http://blog.csdn.net/u013649253/article/details/46240861