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) otin 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 kin[-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 mid 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));
}
原文地址:https://www.cnblogs.com/cjoierShiina-Mashiro/p/12678379.html