分析:
首先我们从博弈入手,看看什么情况先手必胜
先考虑一条链的情况,假设链长为偶数,即存在中点,先手就可以抢占中点,后手无论怎么走,先手都可以走到其关于中点的对称点上
最后后手无法操作,先手必胜
当链长为奇数时,先手两个中点随便抢一个就可以胜利
换在树上,求出直径中点,非直径上的点可以转化为直径上的,效果等价
那么先手必败当且仅当起点为连通块直径的唯一中点
转化一下问题,即一个连通块使得1不是直径唯一中点,即1的儿子的最深深度仅有一个
考虑DP,\(f_{u,i}\)表示\(u\)为根,深度至多为\(i\)的连通块方案数
这个暴力\(O(n^2)\)DP,发现只与最深深度有关,直接长链剖分优化就好了
统计答案时强行钦定某个儿子最深深度为\(D\),其余的不超过\(D\)就好了,维护一个前缀和
复杂度\(O(n)\)
#include<cstdio>
#include<cmath>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<queue>
#include<set>
#include<map>
#include<vector>
#include<string>
#define maxn 2000005
#define MOD 998244353
using namespace std;
inline long long getint()
{
long long num=0,flag=1;char c;
while((c=getchar())<'0'||c>'9')if(c=='-')flag=-1;
while(c>='0'&&c<='9')num=num*10+c-48,c=getchar();
return num*flag;
}
int n;
vector<int>G[maxn];
int cur,pos[maxn],son[maxn],dpt[maxn],mxd[maxn];
long long f[maxn],g[maxn],h[maxn],sum[maxn],pd[maxn];
int tmp[maxn];
inline void dfs1(int u,int fa)
{
dpt[u]=dpt[fa]+1,mxd[u]=dpt[u],g[u]=1;
for(int i=0;i<G[u].size();i++)if(G[u][i]!=fa)
{
dfs1(G[u][i],u),mxd[u]=max(mxd[u],mxd[G[u][i]]);
if(mxd[G[u][i]]>mxd[son[u]])son[u]=G[u][i];
g[u]=g[u]*(g[G[u][i]]+1)%MOD;
}
}
inline void dfs2(int u,int fa)
{
pos[u]=++cur;if(son[u])dfs2(son[u],u);
for(int i=0;i<G[u].size();i++)if(G[u][i]!=fa&&G[u][i]!=son[u])dfs2(G[u][i],u);
}
inline void down(int u,int lim)
{
if(h[u]!=1)
{
f[u]=f[u]*h[u]%MOD;
if(u<lim)h[u+1]=h[u+1]*h[u]%MOD;
h[u]=1;
}
}
inline void solve(int u,int p)
{
f[pos[u]]=h[pos[u]]=sum[pos[u]]=1;
if(son[u])solve(son[u],u);
for(int i=0;i<G[u].size();i++)if(G[u][i]!=p&&G[u][i]!=son[u])
{
int v=G[u][i];solve(v,u);
for(int j=0;j<=mxd[v]-dpt[v];j++)
{
int k=j+1;
down(pos[v]+j,pos[v]+mxd[v]-dpt[v]),sum[pos[v]+j]=((j>0)*sum[pos[v]+j-1]+f[pos[v]+j])%MOD;
if(u==1)continue;
down(pos[u]+k,pos[u]+mxd[u]-dpt[u]),sum[pos[u]+k]=(sum[pos[u]+k-1]+f[pos[u]+k])%MOD;
f[pos[u]+k]=f[pos[u]+k]*((j>0)*sum[pos[v]+j-1]+1)%MOD+f[pos[v]+j]*sum[pos[u]+k-1]%MOD+f[pos[u]+k]*f[pos[v]+j]%MOD;
f[pos[u]+k]%=MOD;
}
if(u==1)continue;
if(mxd[v]<mxd[u])(h[pos[u]+mxd[v]-dpt[u]+1]*=(sum[pos[v]+mxd[v]-dpt[v]]+1))%=MOD;
}
}
int main()
{
n=getint();
for(int i=1;i<n;i++)
{
int u=getint(),v=getint();
G[u].push_back(v),G[v].push_back(u);
}
dfs1(1,0),dfs2(1,0);
solve(1,0);
for(int i=2;i<=mxd[1];i++)down(i,mxd[1]),sum[i]=(i>2)*sum[i-1]+f[i];
long long ans=1;
for(int i=0;i<=n;i++)pd[i]=1,h[i]=1;
for(int i=0;i<G[1].size();i++)
{
int u=G[1][i];
for(int j=2;j<=mxd[u];j++)
{
if(h[j]!=1)pd[j]=pd[j]*h[j]%MOD,h[j+1]=h[j+1]*h[j]%MOD,h[j]=1;
tmp[pos[u]+j-2]=pd[j-1];
}
for(int j=2;j<=mxd[u];j++)pd[j]=pd[j]*(sum[pos[u]+j-2]+1)%MOD;
if (mxd[u]<n)(h[mxd[u]+1]*=(sum[pos[u]+mxd[u]-2]+1))%=MOD;
}
for(int i=0;i<=n;i++)pd[i]=1,h[i]=1;
for(int i=G[1].size()-1;~i;i--)
{
int u=G[1][i];
for(int j=2;j<=mxd[u];j++)
{
if(h[j]!=1)pd[j]=pd[j]*h[j]%MOD,h[j+1]=h[j+1]*h[j]%MOD,h[j]=1;
ans+=tmp[pos[u]+j-2]*f[pos[u]+j-2]%MOD*(pd[j]-pd[j-1])%MOD;
}
for(int j=2;j<=mxd[u];j++)pd[j]=pd[j]*(sum[pos[u]+j-2]+1)%MOD;
if(mxd[u]<n)(h[mxd[u]+1]*=(sum[pos[u]+mxd[u]-2]+1))%=MOD;
}
printf("%lld\n",((g[1]-ans)%MOD+MOD)%MOD);
}