POJ 1741 Tree(点分治点对

时间:2021-12-25 04:19:29

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
题解
求树上总共有多少点对(u,v)距离<=k
题意
初学点分治
树的重心定义:找到一个点,其所有的子树中最大的子树节点数最少,那么这个点就是这棵树的重心,删去重心后,生成的多棵树尽可能平衡
点分治就是把树按子树重心不断DFS,然后处理每个子树对答案的贡献,会用到容斥,把n^2的复杂度优化为nlogn
处理每个子树对答案的贡献,先求出重心到各个点的距离,然后sort一下,然后可以二分出满足<=k的答案
代码
  1 #include<stdio.h>
  2 #include<string.h>
  3 #include<vector>
  4 #include<algorithm>
  5 using namespace std;
  6 
  7 const int maxn=1e4+5;
  8 
  9 vector< pair<int,int> >G[maxn];
 10 int mx[maxn],size[maxn],vis[maxn],dis[maxn],ans,MIN,n,k,num,root;
 11 void dfssize(int u,int fa)
 12 {
 13     size[u]=1;
 14     mx[u]=0;
 15     for(int i=0;i<G[u].size();i++)
 16     {
 17         int v=G[u][i].first;
 18         if(!vis[v]&&v!=fa)
 19         {
 20             dfssize(v,u);
 21             size[u]+=size[v];
 22             mx[u]=max(mx[u],size[v]);
 23         }
 24     }
 25 }
 26 void dfsroot(int r,int u,int fa)//r为子树的根 
 27 {
 28     if(size[r]-size[u]>mx[u])//子树的其余节点 
 29         mx[u]=size[r]-size[u];
 30     if(mx[u]<MIN)//root为重心
 31         MIN=mx[u],root=u;
 32     for(int i=0;i<G[u].size();i++)
 33     {
 34         int v=G[u][i].first;
 35         if(!vis[v]&&v!=fa)
 36             dfsroot(r,v,u);
 37     }
 38 }
 39 void dfsdis(int u,int fa,int d)
 40 {
 41     dis[num++]=d;
 42     for(int i=0;i<G[u].size();i++)
 43     {
 44         int v=G[u][i].first;
 45         int w=G[u][i].second;
 46         if(!vis[v]&&v!=fa)
 47             dfsdis(v,u,d+w);
 48     }
 49 }
 50 int cal(int r,int w)
 51 {
 52     int ret=0;
 53     num=0;
 54     dfsdis(r,r,w);
 55     sort(dis,dis+num);
 56     int L=0,R=num-1;
 57     while(L<R)
 58     {
 59         while(dis[L]+dis[R]>k&&L<R)R--;
 60         ret+=R-L;    
 61         L++;
 62     }
 63     return ret;
 64 }
 65 void dfs(int u)
 66 {
 67     MIN=n;
 68     dfssize(u,u);
 69     dfsroot(u,u,u);
 70     int Grivate=root;
 71     ans+=cal(Grivate,0);
 72     vis[root]=1;
 73     for(int i=0;i<G[Grivate].size();i++)
 74     {
 75         int v=G[Grivate][i].first;
 76         int w=G[Grivate][i].second;
 77         if(!vis[v])
 78         {
 79             ans-=cal(v,w);
 80             dfs(v);
 81         }
 82     }
 83 }
 84 int main()
 85 {
 86     while(scanf("%d%d",&n,&k)!=EOF,n||k)
 87     {
 88         ans=0; 
 89         for(int i=1;i<=n;i++)
 90         {
 91             G[i].clear();
 92             vis[i]=0;
 93         }
 94         for(int i=1,u,v,w;i<n;i++)
 95         {
 96             scanf("%d%d%d",&u,&v,&w);
 97             G[u].push_back({v,w});
 98             G[v].push_back({u,w});
 99         }
100         dfs(1);
101         printf("%d\n",ans);
102     }
103     return 0;
104 }