这道题其实不用换根(我也不会打换根)。
对于(a,b)(c,d)这两条路径,我们考虑有哪些情况:
1. LCA(c,d)在LCA(a,b)的子树中。
2. LCA(c,d)不在LCA(a,b)的子树中。
对于第一种情况,我们要保证LCA(c,d)不在a到b的路径上。
对于第二种情况,c到d的路径不经过连接LCA(a,b)和其父亲的边。
然后就先两次dfs神奇处理出我们需要的东西,代码很好理解。(我也只能理解了)
主要是思维很神奇。
#include<bits/stdc++.h> #define LL long long #define N 3003 #define re register using namespace std; int read() { int x=0,f=1;char s=getchar(); while(s<'0'||s>'9'){if(s=='-')f=-1;s=getchar();} while(s>='0'&&s<='9'){x=x*10+s-'0';s=getchar();} return x*f; } struct EDGE{ int nextt,to; }w[N*2]; int tot=0; int n,p,q; int head[N]; LL fq[N],fp[N];//以i为lca,长度为q/p的路径数 LL gq[N],gp[N];//经过了i与其父亲的连边,长度为q/p的路径数 LL f[N][N],g[N][N];//i的子树中距离根为j的个数,不在i的子树中距离根为j的个数 void add(int a,int b) { tot++; w[tot].nextt=head[a]; w[tot].to=b; head[a]=tot; } //fp,fq,gp,gq更新时均是用了乘法原理 //要有把子树紫薯一个个丢入的前缀思想 void dfs1(int x,int fa) { f[x][0]=1; for(int i=head[x];i;i=w[i].nextt) { int v=w[i].to; if(v==fa)continue; dfs1(v,x); for(int j=1;j<=p;++j)fp[x]+=f[v][p-j]*f[x][j-1]; for(int j=1;j<=q;++j)fq[x]+=f[v][q-j]*f[x][j-1]; for(int j=1;j<=max(q,p);++j)f[x][j]+=f[v][j-1]; } } void dfs2(int x,int fa) { for(int i=1;i<=p;++i)gp[x]+=f[x][p-i]*g[x][i]; for(int i=1;i<=q;++i)gq[x]+=f[x][q-i]*g[x][i]; for(int i=head[x];i;i=w[i].nextt) { int v=w[i].to; if(v==fa)continue; g[v][1]=1; for(int j=2;j<=max(p,q);++j)g[v][j]+=g[x][j-1]+f[x][j-1]-f[v][j-2]; dfs2(v,x); } } int main() { n=read();p=read();q=read(); for(int i=1;i<n;++i) { int a=read(),b=read(); add(a,b);add(b,a); } dfs1(1,1);dfs2(1,1); LL sum1=0,sum2=0; for(int i=1;i<=n;++i)sum1+=fq[i],sum2+=fp[i]; LL ans=sum1*sum2; for(int i=1;i<=n;++i)ans-=(fq[i]*fp[i]+fq[i]*gp[i]+fp[i]*gq[i]); printf("%lld ",ans*4); } /* */