题目链接:poj1741_Tree
题意:
给你一颗n个节点的树,每条边有一个值,问有多少点对(u,v),满足u->v的最短路径小于k。
题解:
典型的树的分治,板子题。
1 #include<cstdio> 2 #include<algorithm> 3 #include<cstring> 4 #define F(i,a,b) for(int i=a;i<=b;++i) 5 using namespace std; 6 7 const int N=1e4+7; 8 9 int n,k,g[N],v[N*2],nxt[N*2],w[N*2],ed,ans; 10 int vis[N],size[N],mx[N],mi,dis[N],tot,root; 11 12 inline void adg(int x,int y,int z){v[++ed]=y,w[ed]=z,nxt[ed]=g[x],g[x]=ed;} 13 void init(){F(i,1,n)g[i]=0,vis[i]=0;ed=ans=0;} 14 15 void dfs_size(int u,int fa) 16 { 17 size[u]=1,mx[u]=0; 18 for(int i=g[u];i;i=nxt[i]) 19 if(v[i]!=fa&&!vis[v[i]]) 20 { 21 dfs_size(v[i],u),size[u]+=size[v[i]]; 22 if(size[v[i]]>mx[u])mx[u]=size[v[i]]; 23 } 24 } 25 26 void dfs_root(int r,int u,int fa) 27 { 28 if(size[r]-size[u]>mx[u])mx[u]=size[r]-size[u]; 29 if(mx[u]<mi)mi=mx[u],root=u; 30 for(int i=g[u];i;i=nxt[i]) 31 if(v[i]!=fa&&!vis[v[i]]) 32 dfs_root(r,v[i],u); 33 } 34 35 void dfs_dis(int u,int d,int fa) 36 { 37 dis[++tot]=d; 38 for(int i=g[u];i;i=nxt[i]) 39 if(v[i]!=fa&&!vis[v[i]]) 40 dfs_dis(v[i],d+w[i],u); 41 } 42 43 int calc(int u,int d) 44 { 45 int ans=0; 46 tot=0,dfs_dis(u,d,0); 47 sort(dis+1,dis+1+tot); 48 int i=1,j=tot; 49 while(i<j) 50 { 51 while(dis[i]+dis[j]>k&&i<j)j--; 52 ans+=j-i,i++; 53 } 54 return ans; 55 } 56 57 void dfs(int u=1) 58 { 59 mi=n,dfs_size(u,0); 60 dfs_root(u,u,0); 61 ans+=calc(root,0),vis[root]=1; 62 for(int i=g[root];i;i=nxt[i]) 63 if(!vis[v[i]])ans-=calc(v[i],w[i]),dfs(v[i]); 64 } 65 66 int main() 67 { 68 while(~scanf("%d%d",&n,&k)&&n+k!=0) 69 { 70 init(); 71 F(i,1,n-1) 72 { 73 int x,y,z; 74 scanf("%d%d%d",&x,&y,&z); 75 adg(x,y,z),adg(y,x,z); 76 } 77 dfs(); 78 printf("%d ",ans); 79 } 80 return 0; 81 }