题目链接
- 阴差阳错之下,赛时居然过了这道题:
- 依次考虑对于mex=1,2,…,n,有多少导出子图满足条件
- 假设mex=k,那么包含0,1,2,…,k-1的导出子图的mex其实不一定是k
- 我们继续拆贡献,每次统计包含0,1,2,…k-1的导出子图的数量时,只累计1的答案,这样就不重不漏了
- 按照题解的描述,这种思想其实是前缀和转化,统计对于mex$\geq$1,2,…,n,有多少导出子图满足条件
- 连通点集:朴素跳树边维护即可
- 可能出现(dpx+1)在模意义下为0的情况,此时需要另外维护0的个数而不能求逆元
#include <bits/stdc++.h>
using namespace std;
const int mod=998244353;
vector<int>a[100005];
int ans,n,p[100005];
int fa[100005];
long long f[100005];
bool e[100005];
void dfs(int n1)
{
f[n1]=1;
for(int i=0;i<a[n1].size();i++)
{
if(a[n1][i]!=fa[n1])
{
fa[a[n1][i]]=n1;
dfs(a[n1][i]);
f[n1]*=(f[a[n1][i]]+1);
f[n1]%=mod;
}
}
}
int main()
{
int T;
cin>>T;
while(T--)
{
n=read1();
for(int i=1;i<=n;i++)
{
a[i].clear();
int w=read1();
p[w]=i;
e[i]=false;
}
for(int i=1;i<n;i++)
{
int u,v;
u=read1();
v=read1();
a[u].push_back(v);
a[v].push_back(u);
}
fa[p[0]]=0;
dfs(p[0]);
long long cur=1;
e[p[0]]=true;
for(int i=0;i<a[p[0]].size();i++)
{
cur*=(f[a[p[0]][i]]+1);
cur%=mod;
}
ans=cur;
for(int i=1;i<n;i++)
{
int q=p[i];
if(e[q]==false)
{
int tmp;
while(fa[q]!=0&&e[q]==false)
{
e[q]=true;
for(int j=0;j<a[q].size();j++)
{
if(a[q][j]!=fa[q]&&e[a[q][j]]==false)
{
cur*=(f[a[q][j]]+1);
cur%=mod;
}
}
tmp=q;
q=fa[q];
}
cur*=power(f[tmp]+1,998244351);
cur%=mod;
}
ans=ans+cur;
ans%=mod;
}
printf("%d\n",ans);
}
return 0;
}