Problem Tree
题目大意
给一棵树,有边权。求树上距离小于等于K的点对有多少。
解题分析
点分治。对每一棵子树进行dfs,求出每棵子树的重心,继而转化为子问题。
对于经过根的路径i--j,令dep为到根距离,那么需求出dep[i]+dep[j]<=k,且i,j属于不同子树,可以求其补集,求出属于同一子树的对答案贡献。
参考程序
1 #include <map> 2 #include <set> 3 #include <stack> 4 #include <queue> 5 #include <cmath> 6 #include <ctime> 7 #include <string> 8 #include <vector> 9 #include <cstdio> 10 #include <cstdlib> 11 #include <cstring> 12 #include <cassert> 13 #include <iostream> 14 #include <algorithm> 15 #pragma comment(linker,"/STACK:102400000,102400000") 16 using namespace std; 17 18 #define N 100008 19 #define LL long long 20 #define lson l,m,rt<<1 21 #define rson m+1,r,rt<<1|1 22 #define clr(x,v) memset(x,v,sizeof(x)); 23 #define bitcnt(x) __builtin_popcount(x) 24 #define rep(x,y,z) for (int x=y;x<=z;x++) 25 #define repd(x,y,z) for (int x=y;x>=z;x--) 26 const int mo = 1000000007; 27 const int inf = 0x3f3f3f3f; 28 const int INF = 2000000000; 29 /**************************************************************************/ 30 31 int n,k,sum,tot,root,ans; 32 int lt[N],f[N],vis[N],size[N],a[N]; 33 struct line{int u,v,w,nt;}eg[N*2]; 34 vector <int> vec; 35 void add(int u,int v,int w) 36 { 37 eg[++sum]=(line){u,v,w,lt[u]}; 38 lt[u]=sum; 39 } 40 void init() 41 { 42 clr(lt,0); sum=1; ans=0; 43 clr(f,0); f[0]=INF; 44 clr(vis,0); 45 } 46 void getRoot(int u,int fa) 47 { 48 size[u]=1; f[u]=0; 49 for (int i=lt[u];i;i=eg[i].nt) 50 { 51 int v=eg[i].v; 52 if (vis[v] || v==fa) continue; 53 getRoot(v,u); 54 size[u]+=size[v]; 55 f[u]=max(f[u],size[v]); 56 } 57 f[u]=max(f[u],tot-size[u]); 58 if (f[u]<f[root]) root=u; 59 } 60 void getDeep(int u,int fa) 61 { 62 vec.push_back(a[u]); 63 for (int i=lt[u];i;i=eg[i].nt) 64 { 65 int v=eg[i].v; 66 if (v==fa || vis[v]) continue; 67 a[v]=a[u]+eg[i].w; 68 getDeep(v,u); 69 } 70 } 71 int cal(int u,int key) 72 { 73 a[u]=key; vec.clear(); 74 getDeep(u,0); 75 sort(vec.begin(),vec.end()); 76 int tmp=0,l=0,r=vec.size()-1; 77 while (l<r) 78 { 79 if (vec[l]+vec[r]<=k) 80 { 81 tmp+=r-l; 82 l++; 83 } 84 else r--; 85 } 86 return tmp; 87 } 88 void work(int u) 89 { 90 ans+=cal(u,0); 91 vis[u]=1; 92 for (int i=lt[u];i;i=eg[i].nt) 93 { 94 int v=eg[i].v; 95 if (vis[v]) continue; 96 ans-=cal(v,eg[i].w); 97 tot=size[v]; root=0; 98 getRoot(v,u); 99 work(root); 100 } 101 } 102 int main() 103 { 104 while (~scanf("%d%d",&n,&k)) 105 { 106 if (n==0) break; 107 init(); 108 rep(i,1,n-1) 109 { 110 int u,v,w; 111 scanf("%d%d%d",&u,&v,&w); 112 add(u,v,w); add(v,u,w); 113 } 114 tot=n; root=0; 115 getRoot(1,0); 116 work(root); 117 printf("%d ",ans); 118 } 119 }