2024初三集训模拟测试3

T1 排序

image
读完题就切了。

T2 牛吃草

点击查看题目

image

很明显的单调队列优化DP。

T3 树上的宝藏

(麻烦,因为换根做的少,如果只是针对这道题,建议看隔壁换根题解。)
image
先不考虑对边进行修改,树形DP处理出每个节点的相关信息。转移感觉有些像前几天的CF1929D

\(f_{i,0/1}\) 表示以 \(i\) 为根节点的子树内是否选 \(i\) 的方案数,\(f_{i,2}\) 表示以 \(i\) 为根的字数内的总方案数。显然有:

\[\large\begin{cases}f_{i,0}=\prod{f_{son_i,2}}\\ f_{i,1}=\prod{f_{son_i,0}}\end{cases} \]

处理出所有初始状态后。
如下图:image
其中左边的数代表不选此节点。
这时有两种做法:

My solution:

发现每个点都对它的父节点有固定的单位影响。

这是每个点对父节点的单位影响:
image

根据上图可以求出,具体来说,从上到下依次为,不选这个点时对父亲不选和选的单位影响以及选这个点时对父亲不选和选的单位影响。

求法也比较简单,就是

\[\begin{cases}val_{0->0}=val_{1->0}=\dfrac{f_{fa,0}}{f_{son,2}}\\ val_{0->1}=\dfrac{f_{fa,1}}{f_{y,0}}\\ val_{1->1}=0\end{cases} \]

此时直接做是 \(O(n^2)\) 的时间复杂度。

考虑将每个点对全局方案数的单位影响,因为已经知道每个点对父亲,所以再 dfs 一遍即可处理出来。具体来说,将根节点 \(1\) 到节点 \(i\) 上的单位影响都合成,设 \(a=val_{0->0,x},b=val_{0->1,x},c=val_{1->0,x},d=val_{1->1,x}\) 式子如下,比较繁琐:

\[\begin{cases}val_{0->0,x}=a\cdot(val_{0->0,fa}+val_{1->1,fa})\\ val_{0->1,x}=a\cdot val_{0->1,fa}+b\cdot val_{1->1,fa}\\ val_{1->0,x}=c\cdot val_{0->0,fa}\\ val_{1->1,x}=c\cdot val_{0->1,fa}\end{cases} \]

这是处理完后的情况:
image

最后就是考虑每条边改变后对答案的影响( \(ans\) 数组),就是对它的父亲的影响乘上父亲对整体答案的单位影响即可。

先处理出当这条边为修改边时对父亲的直接影响,如图
image

然后就做完了,\(ans\) 里存的是每个点对答案的改变值。

#include<bits/stdc++.h>
#define int long long
inline int read(){
	char ch=getchar();int x=0,f=1;
	for(;ch<'0'||ch>'9';ch=getchar())if(ch=='-')f=-1;
	for(;ch>='0'&&ch<='9';ch=getchar())x=(x<<3)+(x<<1)+(ch^48);
	return x*f;
}
const int N=3e5+10,mod=998244353;
int n,f[N][3],fa[N],tot,head[N],val0[N],val1[N],val2[N],ans[N];
int val0_fa[N],val1_fa[N],val2_fa[N],val0_0[N],val0_1[N],val1_0[N],val1_1[N];
std::vector<int> v[N];
inline int qpow(int a,int b){
	int ans=1;
	for(;b;b>>=1,a=a*a%mod)if(b&1)ans=ans*a%mod;
	return ans;
}
inline int ny(int a){return qpow(a,mod-2);}
inline void dfs(int x,int fu){
	fa[x]=fu;
	if(v[x].size()==1&&v[x][0]==fu){f[x][0]=1,f[x][1]=1,f[x][2]=2;}
	int sum=1,mul=1;
	for(int y:v[x]){
		if(y==fu)continue;
		dfs(y,x);
		mul=mul*(f[y][2])%mod;
		sum=sum*f[y][0]%mod;
	}
	f[x][0]=mul,f[x][1]=sum,f[x][2]=(mul+sum)%mod;
	for(int y:v[x]){
		if(y==fu)continue;
		val0_0[y]=val1_0[y]=val0[y]=mul*ny(f[y][2])%mod;
		val0_1[y]=val1[y]=sum*ny(f[y][0])%mod;
		val0_fa[y]=val0[y]*f[y][0]%mod;
		val1_fa[y]=val1[y]*f[y][1]%mod;
		val2_fa[y]=(val0_fa[y]-val1_fa[y]+mod*2)%mod;
		//处理对父亲单位影响和改变后对父亲的影响
	}
}
inline void dfs1(int x,int fu){
	int y=fu;
	if(fu==1)ans[x]=(-val2_fa[x]+mod)%mod;
	else{
		ans[x]=(val1_fa[x]*(val1_0[y]+val1_1[y])%mod-val0_fa[x]*(val0_0[y]+val0_1[y])%mod+2*mod)%mod;
		//这里是 ans 的处理,意义如上。
		int a=val0_0[x],b=val0_1[x],c=val1_0[x],d=val1_1[x];
		val0_0[x]=(a*val0_0[y]%mod+b*val1_0[y]%mod)%mod;
		val0_1[x]=(a*val0_1[y]%mod+b*val1_1[y])%mod;
		val1_0[x]=(c*val0_0[y])%mod;
		val1_1[x]=(c*val0_1[y])%mod;
		//处理对全局的单位影响和 ans
	}
	for(int y:v[x]){
		if(y==fu)continue;
		dfs1(y,x);
	}
}
struct edge{int u,v;}e[N];
signed main(){
	// freopen("in.in","r",stdin),freopen("out.out","w",stdout);
	std::ios::sync_with_stdio(false);std::cin.tie(0),std::cout.tie(0);
	n=read();
	val0[1]=val1[1]=1;
	for(int i=1;i<n;++i){
		int a=read(),b=read();
		v[a].push_back(b),v[b].push_back(a);
		e[++tot].u=a,e[tot].v=b;
	}
	dfs(1,0);
	dfs1(1,0);
	for(int i=1;i<=tot;++i){
		int son;
		if(fa[e[i].u]==e[i].v)son=e[i].u;
		else son=e[i].v;
		std::cout<<(f[1][2]+ans[son]+mod*2)%mod<<'\n';
	}
}
posted @ 2024-02-22 06:55  Ishar-zdl  阅读(57)  评论(2编辑  收藏  举报