https://vjudge.net/contest/161666
难点都在于如何处理出答案已经减掉重复的。
题意:给一个树,路径带权,问两个点距离小于等于给定数k有多少对。
点分治的基础题,算答案的时候因为是单调的所以两头走,
#include<cstring> #include<cstdio> #include<algorithm> #include<cmath> #define rep(i,l,r) for(int i=l;i<=r;i++) #define dow(i,l,r) for(int i=r;i>=l;i--) #define repedge(i,x) for(int i=fi[x];i;i=e[i].next) #define maxn 20020 #define maxm 200010 using namespace std; typedef struct { int v,next,toward; }E; E e[maxm]; int d[maxn],fi[maxn],size[maxn],msize[maxn],vis[maxn],n,tot,total,m,ans; void addedge(int j,int k,int l) { e[++total].toward=k; e[total].next=fi[j]; fi[j]=total; e[total].v=l; } void dfs_len(int x,int fa,int len) { d[++tot]=len; repedge(i,x) { int too=e[i].toward; if (!vis[too] && too!=fa) dfs_len(too,x,len+e[i].v); } } void dfs_size(int x,int fa) { size[x]=1; repedge(i,x) { int too=e[i].toward; if (!vis[too] && too!=fa) { dfs_size(too,x); size[x]+=size[too]; } } } int dfs_root(int x,int fa,int y) { int r1=0; msize[x]=y-size[x]; repedge(i,x) { int too=e[i].toward; if (!vis[too] && too!=fa) { msize[x]=max(msize[x],size[too]); int r2=dfs_root(too,x,y); if (!r1 || msize[r2]<msize[r1]) r1=r2; } } if (!r1 || msize[r1]>msize[x]) r1=x; return r1; } int more(int x,int len) { tot=0; dfs_len(x,0,len); sort(d+1,d+1+tot); int l=0,r=tot,sum=0; while (++l<r) { while (d[l]+d[r]>m && l<r) r--; sum+=r-l; } return sum; } void calc(int x) { int root; dfs_size(x,0); root=dfs_root(x,0,size[x]); ans+=more(root,0); vis[root]=1; repedge(i,root) { int too=e[i].toward; if (!vis[too]) { ans-=more(too,e[i].v); calc(too); } } } int main() { while (~scanf("%d %d",&n,&m)) { if (!n) break; memset(vis,0,sizeof(vis)); memset(fi,0,sizeof(fi)); total=0; rep(i,1,n-1) { int j,k,l; scanf("%d %d %d",&j,&k,&l); addedge(j,k,l); addedge(k,j,l); } ans=0; calc(1); printf("%d\n",ans); } return 0; }