AT5762 Preserve Diameter

Link
首先我们可以发现\(H\)的直径是唯一的,否则不论如何加边都不会使得其直径长度减小。

\(H=(V,E)\)的直径为\((s,t)\),长度为\(l\),建出\(H\)的任意一棵\(s\)为根的bfs树(我们认为\(dep_s=0\)),那么这棵\(H\)满足:
\(1.\forall|dep_u-dep_v|>1,(u,v)\notin E\)
\(1.\forall|dep_u-dep_v|\le1,(u,v)\in E\)
\(3.\{x|dep_x=l\}=\{t\}\)

注意到\(G=(V',E')\)中,所有直径的中点都是同一个(点或边)。不妨认为\(2|l\),这样直径中点就是点\(x\)

对于合法的\(H\),建出以\(x\)为根的bfs树,并求出其\(dep\)数组(依旧认为\(dep_0=0\)),观察发现一个合法的\(H\)会对应两个合法的\(dep\)数组。
因此我们要对合法的\(dep\)数组计数,合法的\(dep\)数组应该满足下列条件:
\(1.\forall k\in[-\frac l2,\frac l2],\exists x,s.t. dep_x=k\)
\(2.\operatorname{ord}(\{x|dep_x=\frac l2\})=\operatorname{ord}(\{x|dep_x=-\frac l2\})=1\)
\(3.\forall(u,v)\in E',|dep_u-dep_v|\le1\)

考虑树形dp,设\(f_{u,0/1/2,0/1/2}\)为只考虑\(u\)子树,存在\(0/1/\ge2\)个点\(v\)满足\(dep_v-dep_u=mx_u\),存在\(0/1/\ge2\)个点\(v\)满足\(dep_u-dep_v=mx_u\)的方案数。其中\(mx_u\)\(u\)子树中的最大深度。
对于\((u,v)\)这条边,枚举\(dep_u-dep_v=-1/0/1\)然后直接转移即可。

还有一种情况是\(2\nmid l\)即中点为一条边\((u,v)\),将这条边断掉之后分别对\(u,v\)两棵子树进行树形dp,然后手动合并即可。

#include<cctype>
#include<cstdio>
#include<vector>
#include<cstring>
const int N=300007,P=998244353,i2=P-P/2;
int m,root,len,fa[N],dia[N],f[N][3][3],g[3][3];std::vector<int>e[N];
void inc(int&a,int b){a+=b-P,a+=a>>31&P;}
int mul(int a,int b){return 1ll*a*b%P;}
int read(){int x=0,c=getchar();while(isspace(c))c=getchar();while(isdigit(c))(x*=10)+=c&15,c=getchar();return x;}
void dfs(int u,int dep)
{
    if(dep>len) len=dep,root=u;
    for(int v:e[u]) if(v^fa[u]) fa[v]=u,dfs(v,dep+1);
}
void dp(int u,int fa,int d)
{
    (d==m/2? f[u][1][1]:f[u][0][0])=1;
    for(int v:e[u])
    {
	if(v==fa) continue;
	dp(v,u,d+1),memset(g,0,36);
	for(int x=0;x<3;++x) for(int y=0;y<3;++y) for(int p=0;p<3;++p) for(int q=0;q<3;++q) for(int k=0,r,t;k<3;++k) r=std::min(2,x+p*(k==1)),t=std::min(2,y+q*(k==2)),inc(g[r][t],mul(f[u][x][y],f[v][p][q]));
	memcpy(f[u],g,36);
    }
}
int main()
{
    int n=read(),p,q;
    for(int i=1,u,v;i<n;++i) u=read(),v=read(),e[u].push_back(v),e[v].push_back(u);
    dfs(1,1),memset(fa+1,0,n<<2),len=0,dfs(root,1);
    for(int i=root;i;i=fa[i]) dia[++m]=i;
    if(m&1) p=dia[m/2+1],dp(p,0,0),printf("%d",mul(i2,f[p][1][1]));
    else p=dia[m/2],q=dia[m/2+1],dp(p,q,1),dp(q,p,1),printf("%d",mul((1ll*f[p][1][0]+f[p][1][1]+f[p][1][2])%P,(1ll*f[q][1][0]+f[q][1][1]+f[q][1][2])%P));
}
posted @ 2020-04-11 11:24  Shiina_Mashiro  阅读(315)  评论(0编辑  收藏  举报