【题意】给了一颗树,问树上任意两个点瞒住dis(u,v)<=k的点对数。在树分治的论文上看到这个题,了解了什么叫做树的重心,老老实实学会了树的重心改怎么求,至于基于树的重心的点分治理解了很久,感觉还是一知半解。爱,要加强训练的强度了,再过段时间就是网络赛了,因此,更要加油了,先把这个球重心和基本的树分治放在这里!
【AC代码】
#include <stdio.h> #include <string.h> #include <assert.h> #include <iostream> #include <algorithm> using namespace std; //Tree Divide And Conquer. //focus is root. const int maxn = 11111; const int maxm = 55555; struct Edge{ int v,w,next; Edge(){} Edge(int v,int w,int next):v(v),w(w),next(next){} }E[maxm]; int tot,head[maxn]; int n,k,vis[maxn],ans,num,root; void Init() { ans=0,tot=0; memset(vis,0,sizeof(vis)); memset(head,-1,sizeof(head)); } void Add_Edge(int u,int v,int w) { E[tot].v=v,E[tot].w=w,E[tot].next=head[u],head[u]=tot++; } // 重心 最大的最小 int mx[maxn],siz[maxn],mi,dis[maxn]; void dfssize(int u,int fa)//get size. { siz[u]=1,mx[u]=0; for(int i=head[u]; ~i; i=E[i].next){ int v = E[i].v; if(v!=fa&&!vis[v]) { dfssize(v,u); siz[u]+=siz[v]; if(siz[v]>mx[u]) mx[u] = siz[v]; } } } void dfsroot(int r,int u,int fa)//求重心 { if(siz[r]-siz[u]>mx[u]) mx[u] = siz[r]-siz[u]; if(mx[u]<mi) root=u,mi=mx[u]; for(int i=head[u]; ~i; i=E[i].next){ int v=E[i].v; if(v!=fa&&!vis[v]) { dfsroot(r,v,u); } } } void dfsdis(int u,int fa,int d)//求距离 { dis[num++]=d; for(int i=head[u]; ~i; i=E[i].next){ int v=E[i].v; if(v!=fa&&!vis[v]){ dfsdis(v,u,d+E[i].w); } } } int cal(int u,int d) { int sum=0; num=0; dfsdis(u,0,d); sort(dis,dis+num); int i=0,j=num-1; while(i<j) { while(dis[i]+dis[j]>k&&i<j) j--; sum+=j-i; i++; } return sum; } void dfs(int u) { mi=n; dfssize(u,0); dfsroot(u,u,0); ans += cal(root,0); vis[root] = 1; for(int i=head[root]; ~i; i=E[i].next){//head[root] int v=E[i].v; if(!vis[v]){ ans-=cal(v,E[i].w); dfs(v); } } } int main() { while(~scanf("%d%d",&n,&k)) { if(n==0&&k==0)break; Init(); int u,v,w; for(int i=1; i<=n-1; i++) { scanf("%d%d%d",&u,&v,&w); Add_Edge(u,v,w); Add_Edge(v,u,w); } dfs(1); printf("%d\n",ans); } return 0; }