POJ 1741 树的点分治

题目大意:

树上找到有多少条路径的边权值和>=k

这里在树上进行点分治,需要找到重心保证自己的不会出现过于长的链来降低复杂度

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <iostream>
 4 #include <vector>
 5 #include <algorithm>
 6
 7 using namespace std;
 8 #define N 10005
 9 int n , m , k , first[N];
10
11 struct Edge{
12     int y , next , d;
13     Edge(){}
14     Edge(int y , int next , int d):y(y),next(next),d(d){}
15 }e[N<<1];
16
17 void add_edge(int x , int y , int d)
18 {
19     e[k] = Edge(y , first[x] , d);
20     first[x] = k++;
21 }
22
23 int sz[N] , dis[N] , f[N] , d[N] , cnt , root , ret;
24 bool use[N];
25
26 void find_root(int u , int fa , int size)
27 {
28     sz[u] = 1 , f[u] = 0;
29     int v;
30     for(int i=first[u] ; ~i ; i=e[i].next){
31         if(use[v=e[i].y] || v==fa) continue;
32         find_root(v , u , size);
33         sz[u] += sz[v] ;
34         f[u] = max(f[u] , sz[v]);
35     }
36     f[u] = max(f[u] , size-sz[u]);
37     if(f[u]<f[root]) root = u;
38 }
39
40 void dfs(int u , int fa)
41 {
42     d[cnt++] = dis[u];
43     sz[u] = 1;
44     int v;
45     for(int i=first[u] ; ~i ; i=e[i].next){
46         if(use[v=e[i].y] || v==fa) continue;
47         dis[v] = dis[u]+e[i].d;
48         if(dis[v]>m) continue;
49         dfs(v , u);
50         sz[u] += sz[v];
51     }
52 }
53
54 int cal(int u , int val)
55 {
56     dis[u] = val , cnt=0;
57     dfs(u , 0);
58     sort(d , d+cnt);
59     int ret = 0;
60     for(int l=0 , r=cnt-1 ; l<r ; )
61         if(d[l]+d[r]<=m) ret+=r-l++;
62         else r--;
63     return ret;
64 }
65
66 void solve(int u)
67 {
68     ret+=cal(u , 0);
69     use[u] =true;
70     int v;
71     for(int i=first[u] ; ~i ; i=e[i].next){
72         if(use[v=e[i].y]) continue;
73         ret -= cal(v , e[i].d);
74         find_root(v , root=0 , sz[v]);
75         solve(root);
76     }
77 }
78
79 int main()
80 {
81    // freopen("in.txt" , "r" , stdin);
82     int x,y,d;
83     while(scanf("%d%d" , &n , &m) , n+m)
84     {
85         memset(first , -1 , sizeof(first));
86         k = 0;
87         for(int i=1 ; i<n ; i++){
88             scanf("%d%d%d" , &x , &y , &d);
89             add_edge(x , y , d);
90             add_edge(y , x , d);
91         }
92         memset(use , 0 , sizeof(use));
93         ret=0 , f[0] = 1e9;
94         find_root(1 , root=0 , n);
95         solve(root);
96         printf("%d\n" , ret);
97     }
98 }
时间: 2024-10-16 03:08:18

POJ 1741 树的点分治的相关文章

poj 1741 树的点分治(入门)

Tree Time Limit: 1000MS   Memory Limit: 30000K Total Submissions: 18205   Accepted: 5951 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

POJ 1741 Tree (树上点分治)(楼教主男人八题之一)

题目地址:POJ 1741 树分治第一发! 树分治详情请看漆子超的国家集训队论文,论文传送门 树分治裸题. 代码如下: #include <iostream> #include <string.h> #include <math.h> #include <queue> #include <algorithm> #include <stdlib.h> #include <map> #include <set> #

POJ 1741 树分治(点分治模板题)

POJ 1741 题意:求一棵树中点对<=k的数量. 总结:点分治,搞不太懂..大概敲了一遍 #include<iostream> #include<cstdio> #include<cstdlib> #include<algorithm> #include<cstring> #include<string> #include<cmath> #include<queue> #include<stac

POJ 1741 树分治

题目链接[http://poj.org/problem?id=1741] 题意: 给出一颗树,然后寻找点对(u,v)&&dis[u][v] < k的对数. 题解: 这是一个很经典的树分治的题.假设我们选择了一个参考点u,那么对于不同的点对(u,v),(u , v)之间的路径有两种情况,经过点u,和不经过点u,加入我算出了没有经过点u的对数,然后把经过点u的加起来就是答案了,很简单,这就是分治的思想.具体看代码. #include<cstdio> #include<c

POJ 1741 树上的点分治

题目大意: 找到树上点对间距离不大于K的点对数 这是一道简单的练习点分治的题,注意的是为了防止点分治时出现最后分治出来一颗子树为一条直线,所以用递归的方法求出最合适的root点 1 #include <cstdio> 2 #include <cstring> 3 #include <iostream> 4 #include <vector> 5 #include <algorithm> 6 7 using namespace std; 8 #de

树的点分治 (poj 1741, 1655(树形dp))

poj 1655:http://poj.org/problem?id=1655 题意: 给无根树,  找出以一节点为根,  使节点最多的树,节点最少. 题解:一道树形dp,先dfs 标记 所有节点的子树的节点数. 再dfs  找出以某节点为根的最大子树,节点最少. 复杂度(n) /***Good Luck***/ #define _CRT_SECURE_NO_WARNINGS #include <iostream> #include <cstdio> #include <cs

poj 1741 楼教主男人八题之一:树分治

http://poj.org/problem?id=1741 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

poj 1741 Tree(树的点分治)

poj 1741 Tree(树的点分治) 给出一个n个结点的树和一个整数k,问有多少个距离不超过k的点对. 首先对于一个树中的点对,要么经过根结点,要么不经过.所以我们可以把经过根节点的符合点对统计出来.接着对于每一个子树再次运算.如果不用点分治的技巧,时间复杂度可能退化成\(O(n^2)\)(链).如果对于子树重新选根,找到树的重心,就一定可以保证时间复杂度在\(O(nlogn)\)内. 具体技巧是:首先选出树的重心,将重心视为根.接着计算出每个结点的深度,以此统计答案.由于子树中可能出现重复

【POJ 1741】 Tree (树的点分治)

Tree 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)