POJ 1741 树形dp
2016-03-10 16:03
330 查看
#include <cstdio> #include <cstring> #include <algorithm> using namespace std; const int Maxn = 2E5 + 10; const int Maxm = 1E5 + 10; const int INF = 0x3f3f3f3f; int N, K, first[Maxm], x, y, z, Next[Maxm], v[Maxm], w[Maxm], cnt, res, q[Maxn], fa[Maxn], p[Maxn], del[Maxn], size[Maxn]; void add(int x, int y, int z) { v[cnt] = y, w[cnt] = z, Next[cnt] = first[x], first[x] = cnt++; } int findroot(int cur) { int i, j, x, rear = 0, Max, min = INF, root; q[rear ++] = cur, fa[cur] = 0; for (i = 0; i < rear; i ++) { x = q[i]; for (j = first[x]; j != -1; j = Next[j]) if (!del[v[j]] && v[j] != fa[x]) q[rear ++] = v[j], fa[v[j]] = x; } for (i = rear - 1; i >= 0; i --) { x = q[i]; size[x] = 1, Max = 0; for (j = first[x]; j != -1; j = Next[j]) if (!del[v[j]] && v[j] != fa[x]) size[x] += size[v[j]], Max = max(Max, size[v[j]]); Max = max(Max, rear - size[x]); if (Max < min) min = Max, root = x; } return root; } int deal(int s, int t) { int i, rear = t, ans = 0; for (i = s; i <= t; i ++) { while (rear >= s && p[rear] + p[i] > K) -- rear; ans += rear - s + 1; } return ans; } void renew(int s, int cur, int d) { int i, j, x, rear = 0; q[rear ++] = cur, fa[cur] = 0, p[s] = d; for (i = 0; i < rear; i ++) { x = q[i]; for (j = first[x]; j != -1; j = Next[j]) if (!del[v[j]] && v[j] != fa[x]) p[s + rear] = p[s + i] + w[j], q[rear ++] = v[j], fa[v[j]] = x; } sort(p + s, p + s + rear); } int dfs(int s, int cur, int d) { int i, root, n, tot = 1; root = findroot(cur); del[root] = 1; for (i = first[root]; i != -1; i = Next[i]) if (!del[v[i]]) { n = dfs(s + tot, v[i], w[i]); res -= deal(s + tot, s + tot + n - 1); tot += n; } p[s] = 0; sort(p + s, p + s + tot); res += deal(s, s + tot - 1) - 1; del[root] = 0; renew(s, cur, d); return tot; } int main(int argc, char const *argv[]) { while (~scanf("%d%d", &N, &K) && N + K) { cnt = 0; res = 0; memset(first, -1, sizeof(first)); for (int i = 1; i < N; i++) scanf("%d%d%d", &x, &y, &z), add(x, y, z), add(y, x, z); dfs(0, 1, 0); printf("%d\n", res >> 1); } return 0; }
恩,楼教主的八题之一,需要优化的树形dp,具体思路有漆子超的《分治算法在树的路径问题中的应用》这篇论文。
题解思路来自:http://blog.sina.com.cn/s/blog_6d5aa19a0100o73m.html
//__________________________________________________________
对于一棵有根树, 树中满足要求的一个数对所对应的一条路径,必然是以下两种情况之一:
1、经过根节点
2、不经过根节点,也就是说在根节点的一棵子树中
对于情况2,可以递归求解,下面主要来考虑情况1。
设X为满足i<j且Depth[i]+Depth[j]<=K的数对(i,j)的个数
设Y为满足i<j,Depth[i]+Depth[j]<=K且Belong[i]=Belong[j]数对(i,j)的个数
那么我们要统计的量便等于X-Y
求X、Y的过程均可以转化为以下问题:
已知A[1],A[2],...A[m],求满足i<j且A[i]+A[j]<=K的数对(i,j)的个数
对于这个问题,我们先将A从小到大排序。
设B[i]表示满足A[i]+A[p]<=K的最大的p(若不存在则为0)。我们的任务便转化为求出A所对应的B数组。那么,若B[i]>i,那么i对答案的贡献为B[i]-i。
显然,随着i的增大,B[i]的值是不会增大的。利用这个性质,我们可以在线性的时间内求出B数组,从而得到答案。
综上,设递归最大层数为L,因为每一层的时间复杂度均为“瓶颈”——排序的时间复杂度O(NlogN),所以总的时间复杂度为O(L*NlogN)
//_________________________________________________________________________________________________________
相关文章推荐
- ThinkPHP邮件发送函数
- iOS通过dSYM文件分析crash
- core dump定位错误位置
- JS Array.join 的使用
- 【网络流+可持久化线段树】[UOJ#77/BZOJ3218]A+B Problem
- C++ 和 C# 开发类型对应信息
- Oracle学习笔记--3、基本函数的使用
- 【Android疑难杂症】GridView动态设置Item的宽高导致第一个Item不响应或显示不正常的问题
- Mac下配置环境变量
- My First Day In New Office
- iOS 利用长按手势移动 Table View Cells
- 引用程序集没有强名称解决办法
- IT十八掌作业_java基础第七天_匿名内部类、异常、包和jar
- JS Array.reverse 将数组元素颠倒顺序
- git远程操作详解和一篇比较好的教程网站地址
- 以boost::function和boost:bind取代虚函数
- ThinkPHP3.2.2 无刷新上传插件uploadify 使用
- HashMap、HashTable和HashSet的理解与比较
- Android组件间通信
- caffe学习网站