hdu 5449 Robot Dog(期望+lca)
2015-09-29 16:09
411 查看
hdu 5449 Robot Dog(期望+lca)
题目链接:hdu 5449 Robot Dog解题思路
n有50000,询问次数有100,每次询问的路径点数最多有100,对于不同询问去做动态规划,开一个dp[u][i]表示在第u个节点匹配了i个的期望,显然最坏情况下dp数组的每个状态都要遍历到,复杂度为o(nqp),不能接受。换个想法,如果我们能知道从节点i走到节点j的期望值dis[[i][j],那么对于每次询问只要按照treasure的位置顺序依次加上相应的期望值即可。不过n很大,预处理每棵树的复杂度为o(n2),也不能接受。但是dis[i][j]的值其实就从节点i到节点j路径上边的期望权值(注意dis[i][j]≠dis[j][i])所以,如果我们能分别算出每条边双向移动的代价,剩下的利用树的前缀性质就可以在log(n)的复杂度内计算出路径上的期望值。
既以0节点为根,处理出up数组(每个节点移动到节点0的代价),dn数组(0移动到每个节点的代价),然后对于路径u−>v,权值
w=up[u]−up[lca(u,v)]+dn[v]−dn[lca(u,v)]
现在问题只剩如何求一条边的移动代价,假设我们求从u节点移动到u的父亲节点,即up[u](son[u]表示u节点的孩子节点个数,直接相连的,Su表示u节点孩子节点的集合,直接相连)
up[u]=1+∑i∈Su(up[i]+up[u])son[u]+1
两边同乘son[u]+1,得:
(son[u]+1)∗up[u]=son[u]+1+∑i∈Su(up[i]+up[u])
(son[u]+1)∗up[u]=son[u]+1+∑i∈Su(up[i])+son[u]∗up[u]
up[u]=son[u]+1+∑i∈Su(up[i])
如果u为叶子节点,那么son[u] = 0,up[u]=1
如果u不为叶子节点,那么将up[i]一直展开,最后肯定剩下的是叶子节点。在展开的过程中,一定会遍历到以u节点为根的子树中的所有节点,并且只遍历一次。(sz[u]表示u子树的节点个数,Tu表示u子树节点的集合)
up[u]=∑i∈Tu(son[i]+1)
up[u]=∑i∈Tu(son[i])+sz[u]
在u子树中,每个节点都是唯一节点的孩子节点(直接连接),除了根以外,所以∑i∈Tu(son[i])=sz[u]−1,带回得:
up[u]=2∗sz[u]−1
同理可求dn[u]
代码
#include <cstdio> #include <cstring> #include <algorithm> using namespace std; typedef long long ll; const int maxn = 50005; int N, E, first[maxn], jump[maxn<<1], linker[maxn<<1]; ll sz[maxn], up[maxn], dn[maxn], f[20][maxn], dep[maxn]; void addEdge(int u, int v) { jump[E] = first[u]; linker[E] = v; first[u] = E++; } void dfs (int u, int far, int d) { sz[u] = 1; dep[u] = d; f[0][u] = far; for (int i = first[u]; i + 1; i = jump[i]) { int v = linker[i]; if (v == far) continue; dfs(v, u, d + 1); sz[u] += sz[v]; } } void dfs (int u) { if (f[0][u] != -1) { up[u] = up[f[0][u]] + 2 * sz[u] - 1; dn[u] = dn[f[0][u]] + 2 * (N-sz[u]) - 1; } else up[u] = dn[u] = 0; for (int i = first[u]; i + 1; i = jump[i]) { int v = linker[i]; if (v == f[0][u]) continue; dfs(v); } } int lca(int u, int v) { if (dep[u] < dep[v]) swap(u, v); int d = dep[u] - dep[v]; for (int i = 0; i < 20; i++) if ((1<<i)&d) u = f[i][u]; if (u == v) return u; for (int i = 19; i >= 0; i--) { if (f[i][u] != f[i][v]) { u = f[i][u]; v = f[i][v]; } } return f[0][u]; } void init () { E = 0; memset(first, -1, sizeof(first)); int u, v; scanf("%d", &N); for (int i = 1; i < N; i++) { scanf("%d%d", &u, &v); addEdge(u, v); addEdge(v, u); } dfs(0, -1, 0); dfs(0); for (int k = 1; k < 20; k++) { for (int i = 0; i < N; i++) f[k][i] = f[k-1][f[k-1][i]]; } } ll get (int u, int v) { int l = lca(u, v); return up[u] - up[l] + dn[v] - dn[l]; } void solve () { int q, p, u, v; scanf("%d", &q); while (q--) { ll ans = 0; scanf("%d%d", &p, &u); while (p--) { scanf("%d", &v); ans += get(u, v); u = v; } printf("%lld.0000\n", ans); } } int main () { int cas; scanf("%d", &cas); while (cas--) { init(); solve(); if (cas) printf("\n"); } return 0; }
相关文章推荐
- HDU 1568
- HDU1290
- HDU1568(Fobonacci公式)
- HDU ACM Step 2.2.2 Joseph(约瑟夫环问题)
- HDU 1405
- HDU 1297
- hdu 1205
- hdu 2087
- hdu 1016
- HDU 4898 The Revenge of the Princess’ Knight ( 2014 Multi-University Training Contest 4 )
- HDU 5240 Exam (好水的题)
- HDU5237 Base64 大模拟
- HDU 1000
- HDU 1001
- hdu-5385
- hdu-5405
- hdu-5490
- HDU 1622 Trees On The Level
- HDU 1063 Exponentiation
- Hdu5033