POJ 1741|BZOJ 1468|Tree|树分治
2016-03-23 22:55
471 查看
求树上距离不超过K的点对数。
一条链有2种情况:
经过根,两端点在子树中
这种就包含了经过根节点而且向父亲延伸的情况。
然后又有两种情况
两端点在根的一个子树中
不合法,因为这样距离不是最短
两端点在根的不同子树中
答案就是本情况的种类数。但似乎不好计算。
可以考虑直接统计2种情况的总方案数再减去情况1的方案数。
总方案数的求法很简单,统计根到子树中所有点的距离,然后按距离排序,枚举左端点,而右端点是单调不升,所以复杂度为O(nlogn)。
而统计情况1可以转化为求总情况(根到LCA间距只影响K)。
整个在子树中
递归处理转化为情况1
为了保证复杂度,需要实时求重心。
所谓树分治,就是确定某个点对答案的贡献度,一旦确定,这个点就可以扔了,毕竟我们不需要再统计它一次。而与某个点有关联的点的个数会随着分治层数的增加而减少,而每次至少减少一半,所以复杂度:
T(n)=xT(nx)+O(nlogn)=O(nlog2n)
其中x≥2。
Total Submissions: 16116 Accepted: 5249
Define dist(u,v)=The min distance between node u and v.
Give an integer k,for every pair (u,v) of vertices is called valid if and only if dist(u,v) not exceed k.
Write a program that will count how many pairs which are valid for a given tree.
The last test case is followed by two zeros.
一条链有2种情况:
经过根,两端点在子树中
这种就包含了经过根节点而且向父亲延伸的情况。
然后又有两种情况
两端点在根的一个子树中
不合法,因为这样距离不是最短
两端点在根的不同子树中
答案就是本情况的种类数。但似乎不好计算。
可以考虑直接统计2种情况的总方案数再减去情况1的方案数。
总方案数的求法很简单,统计根到子树中所有点的距离,然后按距离排序,枚举左端点,而右端点是单调不升,所以复杂度为O(nlogn)。
而统计情况1可以转化为求总情况(根到LCA间距只影响K)。
整个在子树中
递归处理转化为情况1
为了保证复杂度,需要实时求重心。
所谓树分治,就是确定某个点对答案的贡献度,一旦确定,这个点就可以扔了,毕竟我们不需要再统计它一次。而与某个点有关联的点的个数会随着分治层数的增加而减少,而每次至少减少一半,所以复杂度:
T(n)=xT(nx)+O(nlogn)=O(nlog2n)
其中x≥2。
#include <cstdio> #include <algorithm> #include <cstring> const int N = 10005, M = 50005; #define adj(i,j) for(int i=h[j];i;i=p[i])if(v[i]!=fa&&!vis[v[i]]) using namespace std; int h , p[M], w[M], v[M], cnt = 0; int n, k, vis , ans, rt, c; void add(int a, int b, int c) { v[++cnt] = b; w[cnt] = c; p[cnt] = h[a]; h[a] = cnt; } int mx , sz , mi, dis ; void dfssize(int x, int fa) { sz[x] = 1; mx[x] = 0; adj(i,x) { dfssize(v[i], x); sz[x] += sz[v[i]]; if (sz[v[i]] > mx[x]) mx[x] = sz[v[i]]; } } void dfsrt(int r, int x, int fa) { if (sz[r] - sz[x] > mx[x]) mx[x] = sz[r] - sz[x]; if (mx[x] < mi) mi = mx[x], rt = x; adj(i,x) dfsrt(r, v[i], x); } void dfsdis(int x, int d, int fa) { dis[c++] = d; adj(i,x) dfsdis(v[i], d + w[i], x); } int calc(int x, int d) { int ans = 0; c = 0; dfsdis(x, d, 0); sort(dis, dis + c); for (int i = 0, j = c - 1; i < j; ++i) { for (; dis[i] + dis[j] > k && i < j; --j); ans += j - i; } return ans; } void dfs(int x) { int fa = 0; mi = n; dfssize(x, fa); dfsrt(x, x, fa); ans += calc(rt, 0); vis[rt] = 1; adj(i, rt) { ans -= calc(v[i], w[i]); dfs(v[i]); } } int main() { int u, v, w, i; while(scanf("%d%d", &n, &k) != EOF && (n || k)) { memset(vis, 0, sizeof vis); memset(h, 0, sizeof h); cnt = ans = 0; for (i = 1; i < n; i++) { scanf("%d%d%d", &u, &v, &w); add(u, v, w); add(v, u, w); } dfs(1); printf("%d\n", ans); } return 0; }
Tree
Time Limit: 1000MS Memory Limit: 30000KTotal Submissions: 16116 Accepted: 5249
Description
Give a tree with n vertices,each edge has a length(positive integer less than 1001).Define dist(u,v)=The min distance between node u and v.
Give an integer k,for every pair (u,v) of vertices is called valid if and only if dist(u,v) not exceed k.
Write a program that will count how many pairs which are valid for a given tree.
Input
The input contains several test cases. The first line of each test case contains two integers n, k. (n<=10000) The following n-1 lines each contains three integers u,v,l, which means there is an edge between node u and v of length l.The last test case is followed by two zeros.
Output
For each test case output the answer on a single line.Sample Input
5 4 1 2 3 1 3 1 1 4 2 3 5 1 0 0
Sample Output
8
相关文章推荐
- ”WinForm上位机+OV7670摄像头+STM32+蓝牙“图像采集系统(二)PC-MCU蓝牙通信及WinForm上位机开发
- 20160325系统集成管理工程师(test2)
- [3752]:Is the one been second-killed first?
- Java SE、Java EE、Java ME 简介
- c++中的基础概念
- quartz mysql , shiro logout
- 梯度下降法综述
- There is no getter for property named 'id' in 'class java.lang.Integer'
- 欢迎使用CSDN-markdown编辑器
- mysql触发器
- Activity intent intent filter 广播接收器的区别
- java_patest甲级真题1002. A+B for Polynomials
- LocalBroadcastManager
- React-Native系列Android——自定义View组件开发
- C# 类和结构的区别
- JS操作SVG模拟水滴分离、融合效果
- 你如何对网站的文件和资源进行优化?
- iOS UITextField的基本用法
- 倒计时时钟
- LINUX内核设计第五周——扒开系统调用的三层皮(下)