ALGORITHM NOTE / ARCHIVE
2024杭电多校6——1007树上MEX问题
做一些对官方题解的补充: 1.为什么问题可以转化为求的连通块数量, 题目让我们求所有连通导出子图MEX之和,可能存在的答案有1,2......n,对于,它的贡献是的联通子图数量乘上MEX, 所以答案, 记 , 所以,
做一些对官方题解的补充:
1.为什么问题可以转化为求的连通块数量,
题目让我们求所有连通导出子图MEX之和,可能存在的答案有1,2......n,对于,它的贡献是的联通子图数量乘上MEX,
所以答案,
记 ,
所以,
而 这个式子换个形式就是,也就是要求的答案,(如果不理解的话带个n进去,自己展开写一下就明白了) 至于题解里的联想我是不明白,我只能从结果说明二者等价
2.对于求连通块的的dp 只用本身也是一个连通块,所以dp初值是1 为什么是, 1代表不选这棵子树,dp[v]是选择这棵子树的方案数,子树独立,所以乘起来即可
3.为什么是和集合有直接连边但不在集合里的点v,它们的乘起来? 类似于求连通块的dp,相当于把集合缩成一个点,那么这样看不就是求这个点的dp值吗
#include <bits/stdc++.h>
using namespace std;
using i64 = long long;
#define ios ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
const int mod = 998244353;
const int maxn = 1e5+10;
//代码没有考虑(1+dp[x])%mod==0的情况
i64 qp(i64 a,i64 b){
i64 res = 1;
while(b){
if(b&1) res = (res*a)%mod;
b>>=1;
a = (a*a)%mod;
}
return res;
}
int n,ff[maxn],rt,ans,now;
int fa[maxn];
void dfs(int x,int fat,vector<int>&dp,vector<vector<int>> &g){
fa[x] = fat;
for(auto y:g[x]){
if(y==fat) continue;
dfs(y,x,dp,g);
dp[x] = (dp[x]*(1LL+dp[y])%mod)%mod;
}
}
void solve() {
cin>>n;
vector<int>a(n+1);
vector<vector<int>> g(n+1);
for(int i = 1;i<=n;++i){
cin>>a[i];
ff[a[i]] = i;
}
for(int i = 1;i<n;++i){
int x,y;
cin>>x>>y;
g[x].push_back(y);
g[y].push_back(x);
}
vector<int> dp(n+1,1);
rt = ff[0];
dfs(rt,0,dp,g);
ans = dp[rt],now = ans;
stack<int>st;
vector<bool> vis(n+1,0);
vis[rt]=1;
for(int i = 1;i<n;++i){
int u = ff[i];
if(!vis[u]){
while(!vis[u]){
st.push(u);
u = fa[u];
}
while(!st.empty()){
int x = st.top();
st.pop();
vis[x]=1;
now = (1LL*now*(qp((1LL+dp[x])%mod,mod-2)%mod))%mod;
now = (1LL*now*dp[x])%mod;
}
}
ans = (1LL*ans+now)%mod;
}
cout<<ans<<"\n";
}
signed main() {
ios;
int t;
cin >> t;
while (t--) {
solve();
}
return 0;
}
对于处理的情况,题解里给了方法,但是我不会实现,有会的佬教教我