题意:
在一个树上求三个点两两距离相等的方案数。n≤5000。
题解:
枚举每个点作为中心点,求出每个子树的深度为i的节点大小,则目标是求某个深度的答案和。
设第i个子树在某个深度的节点数为dep[i],令a1[i]=sigma(dep[j],j<=i);则取两个节点的答案a2[i]=dep[i]*a1[i-1],取三个节点的答案为a3[i]=dep[i]*a2[i-1]为所求,故递推求即可。
代码:
1 #include <cstdio> 2 #include <cstring> 3 #include <algorithm> 4 #include <queue> 5 #define inc(i,j,k) for(int i=j;i<=k;i++) 6 #define maxn 5010 7 #define ll long long 8 using namespace std; 9 10 inline int read(){ 11 char ch=getchar(); int f=1,x=0; 12 while(ch<'0'||ch>'9'){if(ch=='-')f=-1; ch=getchar();} 13 while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar(); 14 return f*x; 15 } 16 struct e{int t,n;}es[maxn*2]; int g[maxn],ess; 17 void pe(int f,int t){ 18 es[++ess]=(e){t,g[f]}; g[f]=ess; es[++ess]=(e){f,g[t]}; g[t]=ess; 19 } 20 int n,dep[maxn]; ll a1[maxn],a2[maxn],a3[maxn],ans; 21 void dfs(int x,int fa,int d){ 22 dep[d]++; for(int i=g[x];i;i=es[i].n)if(es[i].t!=fa)dfs(es[i].t,x,d+1); 23 } 24 int main(){ 25 n=read(); inc(i,1,n-1){int x=read(),y=read(); pe(x,y);} 26 inc(i,1,n){ 27 int tot=0; memset(a1,0,sizeof(a1)); memset(a2,0,sizeof(a2)); memset(a3,0,sizeof(a3)); 28 for(int j=g[i];j;j=es[j].n){ 29 memset(dep,0,sizeof(dep)); dfs(es[j].t,i,1); tot++; 30 inc(k,1,n){ 31 if(tot>=3){a3[k]+=a2[k]*dep[k]; a2[k]+=a1[k]*dep[k]; a1[k]+=dep[k];} 32 if(tot==2){a2[k]+=a1[k]*dep[k]; a1[k]+=dep[k];} 33 if(tot==1)a1[k]+=dep[k]; 34 } 35 } 36 inc(j,1,n)ans+=a3[j]; 37 } 38 printf("%lld",ans); return 0; 39 }
20161104