poj1741 树上的分治
题意是说给了n个点的树n<=10000,问有多少个点对例如(a,b)他们的之间的距离小于等于k 采用树的分治做
#include <iostream> #include <cstdio> #include <string.h> #include <algorithm> #include <vector> using namespace std; const int maxn=20005; int H[maxn],nx[maxn*2],to[maxn*2],numofE,dist[maxn*2]; void add(int u, int v, int d) { numofE++; dist[numofE]=d, to[numofE]=v, nx[numofE]=H[u], H[u]=numofE; } void init(int N) { numofE=0; memset(H,0,sizeof(H)); } int ans; bool center[maxn]; int subnum[maxn]; int Q[maxn+10],fa[maxn]; int searchroot(int cur) { int rear=0,root=cur; Q[rear++]=cur;fa[cur]=0; for(int i=0; i<rear; i++){ int x= Q[i]; for(int j=H[x]; j; j=nx[j]) if(to[j]!=fa[x]&& center[ to[j] ]==false) Q[rear++]=to[j],fa[to[j]]=x; } int MIN=100000000; for(int i=rear-1; i>=0; i--){ int x=Q[i]; subnum[x]=1; int MA=0; for(int j=H[x]; j ; j=nx[j]) if(to[j]!=fa[x]&¢er[ to[j] ]==false) MA=max(MA,subnum[to[j]]),subnum[x]+=subnum[to[j]]; MA=max(MA,rear-subnum[ x ]); if(MIN>MA)MIN=MA,root=x; } return root; } int P[maxn]; int N,K; int count_pair(int s, int t){ int ge=0,R=t; for(int i=s; i<t; i++) { while(R>s&&P[R-1]+P[i]>K)R--; ge+=R-s-(R>i?1:0); } return ge/2; } void updateedg(int s, int cur, int d) { int rear=0; Q[rear++]=cur; fa[cur]=0;P[s]=d; for(int i=0; i<rear; i++) { int x=Q[i]; for(int j=H[x]; j; j=nx[j]) { int tto=to[j]; if(center[tto]||tto==fa[x])continue; P[s+rear]=P[s+i]+dist[j],Q[rear++]=tto,fa[tto]=x; } } sort(P+s,P+s+rear); } int dfs(int s,int cur,int d) { int root,tot=1; root=searchroot(cur); center[root]=true; for(int i=H[root]; i ; i=nx[i]) { int tto=to[i]; if(center[tto])continue; int n=dfs(s+tot,tto,dist[i]); ans-=count_pair(s+tot,s+tot+n); tot+=n; } P[s]=0; sort(P+s,P+s+tot); ans+=count_pair(s,s+tot); center[root]=false; updateedg(s,cur,d); return tot; } int main() { memset(center,false,sizeof(center)); while(scanf("%d%d",&N,&K)==2) { if(!N&&!K)break; ans=0; init(N); for(int i=1; i<N; i++){ int a,b,d; scanf("%d%d%d",&a,&b,&d); add(a,b,d);add(b,a,d); } dfs(0,1,0); printf("%d\n",ans); } return 0; }