树上 MEX 问题

题目链接

  • 阴差阳错之下,赛时居然过了这道题:
  • 依次考虑对于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;
}
posted @ 2024-08-06 20:14  D06  阅读(52)  评论(0)    收藏  举报
//雪花飘落效果