POJ1751 Tree 树分治

分析:每次找重心可以发现最多n层,每层复杂度是O(nlogn) 总体时间复杂度是O(nlog^2n)

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <vector>
#include <queue>
#include <set>
#include <map>
#include <string>
#include <cmath>
#include <stdlib.h>
using namespace std;
typedef long long LL;
const int N=1e4+5;
int head[N],tot,n,k,ret,cnt,sz[N],rt,p,dis[N],mx[N];
bool vis[N];
struct Edge{
  int v,w,next;
}edge[N<<1];
void add(int u,int v,int w){
  edge[tot].v=v;
  edge[tot].w=w;
  edge[tot].next=head[u];
  head[u]=tot++;
}
void getsz(int u,int f){
  sz[u]=1;mx[u]=0;
  for(int i=head[u];~i;i=edge[i].next){
    int v=edge[i].v;if(v==f||vis[v])continue;
    getsz(v,u);sz[u]+=sz[v];
    if(sz[v]>mx[u])mx[u]=sz[v];
  }
}
void getroot(int tp,int u,int f){
  mx[u]=max(mx[u],sz[tp]-sz[u]);
  if(mx[u]<cnt)cnt=mx[u],rt=u;
  for(int i=head[u];~i;i=edge[i].next){
    int v=edge[i].v;if(v==f||vis[v])continue;
    getroot(tp,v,u);
  }
}
void getdis(int u,int f,int d){
  dis[++p]=d;
  for(int i=head[u];~i;i=edge[i].next){
    int v=edge[i].v;if(v==f||vis[v])continue;
    getdis(v,u,d+edge[i].w);
  }
}
int cal(int u,int d){
  int ans=0;
  p=0;
  getdis(u,-1,d);
  sort(dis+1,dis+1+p);
  for(int i=1,j=p;i<j;++i){
    while(dis[i]+dis[j]>k&&i<j)--j;
    ans+=j-i;
  }
  return ans;
}
void dfs(int u){
  cnt=n;getsz(u,-1);getroot(u,u,-1);
  ret+=cal(rt,0);vis[rt]=true; 
  for(int i=head[rt];~i;i=edge[i].next){
    int v=edge[i].v;if(vis[v])continue;
    ret-=cal(v,edge[i].w);
    dfs(v);
  } 
  
}
int main(){
  while(~scanf("%d%d",&n,&k),n&&k){
     for(int i=1;i<=n;++i)head[i]=-1,vis[i]=false;
     ret=tot=0;
     for(int i=1;i<n;++i){
      int u,v,w;scanf("%d%d%d",&u,&v,&w);
      add(u,v,w);add(v,u,w);
     }
     dfs(1);
     printf("%d\n",ret);
  }
  return 0;
}
View Code

 

posted @ 2016-08-15 22:16  shuguangzw  阅读(186)  评论(0编辑  收藏  举报