点分治就是在树上跑分治。
这个题是求树上两两距离小于K的点对有多少.
可以定义length[i]为i点与根结点的距离。
那么对于其不在同一个根儿子子树的点,这样可以全部计算出来了,现在就差每个子树里的点。也就是说,对于这个根,经过其的点的路径全部算出来了。
此时可以把这个根从图中删掉,那么再递归进行处理后面的根,那么得到的结果即可。
每次都寻找重心来进行分治,这样可以使得复杂度为 nlogn
注意写代码的正确性。。
#include <iostream>
#include <stdio.h>
#include <vector>
#include <string.h>
#include <algorithm>
#include <map>
#include<time.h>
#include<set>
using namespace std;
const int maxn=1e4+7;
struct ttt{
int w,v,next;
}edge[maxn+maxn];
int head[maxn];
int e,n;
bool vis[maxn];
void init(){
e=0;
memset(vis,0,sizeof(vis));
memset(head,-1,sizeof(head));
}
int K;
void add(int u,int v,int w){
e++;
edge[e].v=v;
edge[e].w=w;
edge[e].next=head[u];
head[u]=e;
}
int mx[maxn],size[maxn],mi,root,dis[maxn],num;
//mx用来储存每个结点的最大子树大小,size储存每个结点的子树大小,dis存结点
int dfssize(int u,int fa){ //这个函数预处理全部子树的大小和每个点的最大子树大小
int i,v;
//cout <<" in in " << u << endl;
size[u]=1; //初始大小为1,最大子树大小是0
mx[u]=0;
for(i=head[u];i!=-1;i=edge[i].next){
v=edge[i].v;
// cout <<"!!!"<<v<< endl;
if(v != fa && !vis[v]){
dfssize(v,u);
size[u]+=size[v];
mx[u]=max(size[v],mx[u]);
}
}
// cout <<" OUT OUT " << u << endl;
}
//dfsroot 的fa只用来判不走回去的边,r用来判从进入到这个点的这个方向的点有多少
int dfsroot(int r,int u,int fa){ //r是指最开始dfs的那个点
int i,v;
if(size[r]-size[u]>mx[u])mx[u]=size[r]-size[u]; //这里是考虑从父节点连接下来的那一边
if(mx[u]<mi)mi=mx[u],root=u;//取最大子树最小的那个点作为根
for(i=head[u];i!=-1;i=edge[i].next){
int v=edge[i].v;
if(vis[v]==1||v==fa)continue;
dfsroot(r,v,u);
}
}
int dfsdis(int u,int d,int fa){
dis[num++]=d; //距离为d
int i,v;
for(i=head[u];i!=-1;i=edge[i].next){
v=edge[i].v;
if(vis[v]==1||v==fa)continue;
dfsdis(v,d+edge[i].w,u);
}
}
int calc(int u,int d){//到这个点的距离已经是d了
int ret=0;
num=0;
dfsdis(u,d,0); //从这个点开始计算出全部点的距离
sort(dis,dis+num);
int i=0,j=num-1;
while(i<j){ //双指针扫
while(dis[i]+dis[j]>K&&i<j)j--;
ret+=j-i;i++;
}
return ret;
}
int Sum;
int dfs(int u){
// cout <<"in"<< u<< endl;
mi=n;
dfssize(u,0);
dfsroot(u,u,0);
Sum+=calc(root,0); //以root作为根去找
vis[root]=1;
int i,v;
for(i=head[root];i!=-1;i=edge[i].next){
v=edge[i].v;
if(!vis[v]){ //每次计算的时候会把同一颗子树上点对也计算了,这样子会重复计算,那么每次剪掉即可
Sum-=calc(v,edge[i].w);
dfs(v);
}
}
}
int main(){
int i,j,k,f1,f2,f3,f4,t1,t2,t3,t4,m;
//freopen("in.txt","r",stdin);
while(scanf("%d %d",&n,&m)==2){
if(n+m==0)break;
K=m;init();
for(i=1;i<n;i++){
scanf("%d %d %d",&t1,&t2,&t3);
add(t1,t2,t3);
add(t2,t1,t3);
}
//for(i=head[1];i!=-1;i=edge[i].next){
// cout << edge[i].v <<endl;
//}
Sum=0;
dfs(1);
printf("%d\n",Sum);
}
return 0;
}