poj1741 (点分治)

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 }
View Code
原文地址:https://www.cnblogs.com/rpSebastian/p/5922017.html