POJ 1742.Tree-树分治(点分治) 模板题-区间点对最短距离<=K的点对数量

Time Limit: 1000MS Memory Limit: 30000K
Total Submissions: 34141 Accepted: 11420

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

 

 

题意就是给你一个带边权的树,求树上最短距离<=K的点对数量。树分治模板题。

 

代码:

  1 //树分治-点分治
  2 #include<cstdio>
  3 #include<cstring>
  4 #include<cstdlib>
  5 #include<cstring>
  6 #include<algorithm>
  7 #include<cmath>
  8 using namespace std;
  9 typedef long long ll;
 10 const int inf=1e9+10;
 11 const int maxn=1e5+10;
 12 
 13 int head[maxn],tot;
 14 int root,allnode,ans,n,k;
 15 int vis[maxn],deep[maxn],dis[maxn],siz[maxn],point[maxn];//deep[0]子节点个数(路径长度),point为重心节点
 16 
 17 struct node{
 18     int to,next,val;
 19 }edge[maxn];
 20 
 21 void add(int u,int v,int w)//前向星存图
 22 {
 23     edge[tot].to=v;
 24     edge[tot].next=head[u];
 25     edge[tot].val=w;
 26     head[u]=tot++;
 27 }
 28 
 29 void init()//初始化
 30 {
 31     memset(head,-1,sizeof head);
 32     memset(vis,0,sizeof vis);
 33     tot=0;
 34 }
 35 
 36 void get_root(int u,int father)//重心
 37 {
 38     siz[u]=1;point[u]=0;
 39     for(int i=head[u];~i;i=edge[i].next){
 40         int v=edge[i].to;
 41         if(v==father||vis[v]) continue;
 42         get_root(v,u);//递归得到子树大小
 43         siz[u]+=siz[v];
 44         point[u]=max(point[u],siz[v]);//更新u节点的point
 45     }
 46     point[u]=max(point[u],allnode-siz[u]);//保存节点size
 47     if(point[u]<point[root]) root=u;//更新当前子树的重心
 48 }
 49 
 50 void get_dis(int u,int father)//获取子树所有节点与根的距离
 51 {
 52     deep[++deep[0]]=dis[u];
 53     for(int i=head[u];~i;i=edge[i].next){
 54         int v=edge[i].to;
 55         if(v==father||vis[v]) continue;
 56         int w=edge[i].val;
 57         dis[v]=dis[u]+w;
 58         get_dis(v,u);
 59     }
 60 }
 61 
 62 int cal(int u,int now)
 63 {
 64     dis[u]=now;deep[0]=0;
 65     get_dis(u,0);
 66     sort(deep+1,deep+deep[0]+1);
 67     int all=0;
 68     for(int l=1,r=deep[0];l<r;){
 69         if(deep[l]+deep[r]<=k){
 70             all+=r-l;l++;
 71         }
 72         else r--;
 73     }
 74     return all;
 75 }
 76 
 77 void solve(int u)//以u为重心进行计算
 78 {
 79     vis[u]=1;
 80     ans+=cal(u,0);//以当前u为重心的贡献
 81     for(int i=head[u];~i;i=edge[i].next){
 82         int v=edge[i].to;
 83         if(vis[v]) continue;
 84         ans-=cal(v,edge[i].val);//减去子树的影响
 85         allnode=siz[v];
 86         root=0;
 87         get_root(v,u);
 88         solve(root);
 89     }
 90 }
 91 
 92 int main()
 93 {
 94     while(~scanf("%d%d",&n,&k)&&n&&k){
 95         init();
 96         for(int i=1;i<n;i++){
 97             int u,v,w;
 98             scanf("%d%d%d",&u,&v,&w);
 99             add(u,v,w);
100             add(v,u,w);
101         }
102         root=ans=0;
103         allnode=n;point[0]=inf;
104         get_root(1,0);
105         solve(root);
106         printf("%d\n",ans);
107     }
108     return 0;
109 }

 

转载于:https://www.cnblogs.com/ZERO-/p/11283209.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值