Description
Solution
神仙操作orz。
首先看数据范围,显然不可能是O(n2)的。(即绝对不是枚举那么简单的),我们考虑dp。
定义f(x,k)为以x为根的子树中与x距离为k的节点数;g(x,k)为在以x为根的子树中选择两个点,使得另一个点应在x子树外且离x距离为k的方案数(或者距离为0)。但是这样子暴力转移怕是会崩em,考虑优化。
这里的树是棵静态树,考虑树链剖分,点分治之类的思想。
最后,由于很多时候它的复杂度和树的高度有关,考虑长链剖分。
转移的话,暴力枚举所有轻链(啊我可能说的不是很清楚,类似启发式合并的想法吧)。
那么该点对应的长链怎么办呢?类似树剖的重儿子,我们定义节点x的长儿子为son[x],它是只有一个的。
而假如该点只有一个儿子,f(x,k)=f(son[x],k-1),g(x,k)=g(son[x],k+1)。
还是和树剖一样的思想,我们把同一条长链的信息存在一起,例如把f(son[x],k-1)的信息与f(x,k)存在同一个地址下。(我们能这么做是因为son[x]的信息在被x更新完后它就没用了啊)。g的话同理。
Code
#include<iostream> #include<cstdio> #include<cstring> #include<cmath> using namespace std; typedef long long ll; const int N=50010; int mxdep[N],top[N],fa[N],dep[N],son[N],cnt_f[N],cnt_g[N],cntf=0,cntg=0; ll F[N],G[N<<1]; int getlen(int x){return mxdep[x]-dep[x]+1;} ll &f(int x,int y){return F[cnt_f[top[x]]+dep[x]-dep[top[x]]+y];} ll &g(int x,int y){return G[cnt_g[top[x]]-dep[x]+dep[top[x]]+y];} struct _pas{int y,nxt;}_g[N<<1];int h[N],tot=0; void dfs1(int x,int f) { fa[x]=f;dep[x]=dep[f]+1;mxdep[x]=dep[x];son[x]=0; for (int i=h[x];i;i=_g[i].nxt) if (_g[i].y!=f){ dfs1(_g[i].y,x); mxdep[x]=max(mxdep[x],mxdep[_g[i].y]); if (mxdep[son[x]]<mxdep[_g[i].y]) son[x]=_g[i].y; } } void dfs2(int x) { top[x]=son[fa[x]]==x?top[fa[x]]:x; if (top[x]==x) { int d=getlen(x); cnt_f[x]=cntf;cnt_g[x]=cntg+d; cntf+=d;cntg+=2*d; } if (son[x]) dfs2(son[x]); for (int i=h[x];i;i=_g[i].nxt) if (_g[i].y!=son[x]&&_g[i].y!=fa[x]) dfs2(_g[i].y); } ll ans; void dp(int u) { f(u,0)=1; if (son[u]) dp(son[u]),ans+=g(u,0); for (int i=h[u];i;i=_g[i].nxt) if (_g[i].y!=son[u]&&_g[i].y!=fa[u]) { int v=_g[i].y;dp(v);int len=getlen(v); for (int i=1;i<=len;i++) ans+=g(u,i)*f(v,i-1); for (int i=1;i<len;i++) ans+=g(v,i)*f(u,i-1); for (int i=1;i<=len;i++) g(u,i)+=f(u,i)*f(v,i-1); for (int i=1;i<=len-2;i++) g(u,i)+=g(v,i+1); for (int i=1;i<=len;i++) f(u,i)+=f(v,i-1); } } void _clear() { tot=cntf=cntg=0; memset(h,0,sizeof(h)); memset(F,0,sizeof(F)); memset(G,0,sizeof(G)); } int n,x,y; int main() { while (1) { scanf("%d",&n); if (!n) return 0; _clear(); for (int i=1;i<n;i++) { scanf("%d%d",&x,&y); _g[++tot]=_pas{y,h[x]};h[x]=tot; _g[++tot]=_pas{x,h[y]};h[y]=tot; } ans=0; dfs1(1,0);dfs2(1);dp(1); printf("%lld\n",ans); } }