noip模拟46 *ckw的树

题意

给定一棵树,从一个点可以走到距离不超过2的其他点(包括自己),有若干个终点,问以某个点当起点的期望步数。

思路

我们设 \(E(u)\) 为从 \(u\) 点开始走的期望步数,容易得到
\( E(u)=\frac{E(gfa(u))+E(fa_{u})+\sum_{v\epsilon bro_{u}}E(v)+\sum_{v\epsilon son_{u}}E(v)+\sum_{v\epsilon gson_{u}}E(v)}{du_{u}}+1 \)

(记得加上原地不动的情况)

高斯应该很好解吧,但我们可以考虑能不能消掉几项。
首先我们注意到叶子节点和根节点是少了几项的,考虑是否能根据他们消掉几项。

叶节点:
\( E(u)=\frac{E(gfa_{u})+E(fa_{u})+\sum_{v\epsilon bro_{u}}E(v)}{du_{u}}+1 \)

将他的所有兄弟节点加起来,则:

\( \sum E(u)=\sum a E(gfa_{u})+\sum b E(fa_{u})+\sum c \sum_{v \epsilon bro_{u}}E(v)+f \)

\(a,b,c,f\) 为系数)

因为 \(\sum E(u)=\sum_{v\epsilon bro_{u}}E(v)\), 我们设 \(sum(u)=\sum E(u),A=\sum a,B=\sum b,C=\sum c\)

可以得到:

\( sum(u)=AE(gfa_{u})+BE(fa_{u})+Csum(u)+f \)

\( sum(u)=\frac{AE(gfa_{u})+BE(fa_{u})}{1-C}+f \)

我们把他带入到叶节点的式子,从而消去了 \(c\) 项,现在叶节点仅剩下 \(a,b,f\)
项。
然后再带入总式子,就可以消去 \(son\)\(gson\) 项,注意 \(son\)\(gson\) 的各项与原式各项的对应关系。然后原式就剩下 \(a,b,c,f\) 项,仿照叶节点的方式就可以再消去 \(c\) 项。

最后每个方程仅剩下 \(a,b,f\) 项,从根节点向下扫一边即可求出答案。

Code
#include <bits/stdc++.h>
#define pir make_pair
#define db double
#define int long long
#define re register
using namespace std;
const int maxn=1e5+10;
const int mol=998244353;
inline int read(){
    int x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9') f=(ch=='-')?-1:1,ch=getchar();
    while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
    return x*f;
}

inline int qpow(int a,int b) { int ans=1; while(b){ if(b&1) (ans*=a)%=mol; (a*=a)%=mol; b>>=1; } return ans; }
int n,m,w[maxn],du[maxn],son[maxn];
struct EDGE { int var,nxt; } edge[maxn<<1];
int head[maxn],cnt=1,ansl[maxn];
inline void add(int a,int b) { edge[++cnt]=(EDGE){b,head[a]}; head[a]=cnt; }
struct DATE { int a,b,c,d; } f[maxn],g[maxn];
inline void dfs1(int now,int fa,int ff,int e) {
	du[now]=son[fa]+(fa>0)+(ff>0);
	son[now]=0ll;
	int A=0ll,B=0ll,C=1ll,D=0ll;
	for(re int i=head[now],to;i;i=edge[i].nxt) if(i!=e) son[now]++;
	for(re int i=head[now],to;i;i=edge[i].nxt) if(i!=e) { 
		to=edge[i].var;
		dfs1(to,now,fa,i^1);
		(du[now]+=(son[to]+1)%mol)%=mol;
		(A+=f[to].a)%=mol; (B+=f[to].b)%=mol; (C+=mol-f[to].c)%=mol; (D+=f[to].d)%=mol; 
	}
	int sd=qpow(du[now],mol-2);
	f[now].a=f[now].b=f[now].c=sd; f[now].d=1ll;
	int sc=(C!=0)? qpow(C,mol-2):0ll;
	int l=1ll;
	(A*=sc)%=mol; (B*=sc)%=mol; (D*=sc)%=mol; 
	for(re int i=head[now],to;i;i=edge[i].nxt) if(i!=e) {
		to=edge[i].var;
		(f[to].a+=A*f[to].c%mol)%=mol;
		(f[to].b+=B*f[to].c%mol)%=mol;
		(f[to].d+=D*f[to].c%mol)%=mol;
		f[to].c=0ll;
		
		(f[now].b+=f[to].a*(g[to].b+1ll)%mol*sd%mol)%=mol;
		(f[now].d+=f[to].d*(g[to].b+1ll)%mol*sd%mol)%=mol;
		(l+=mol-f[to].b*(g[to].b+1ll)%mol*sd%mol)%=mol;
		
		(f[now].d+=g[to].d*sd%mol)%=mol;
		(l+=mol-g[to].a*sd%mol)%=mol;
		
		(g[now].a+=f[to].a)%=mol; (g[now].b+=f[to].b)%=mol; (g[now].d+=f[to].d)%=mol;
	}
	if(!w[now]) {
		int sl=qpow(l,mol-2);
		(f[now].a*=sl)%=mol; (f[now].b*=sl)%=mol; (f[now].c*=sl)%=mol; (f[now].d*=sl)%=mol;
	} else { f[now].a=f[now].b=f[now].c=f[now].d=0ll; }
}
inline void dfs2(int now,int l1,int l2,int e) {
	ansl[now]=((f[now].b*l1%mol+f[now].a*l2%mol)%mol+f[now].d)%mol;
	for(re int i=head[now];i;i=edge[i].nxt) if(i!=e) {
		dfs2(edge[i].var,ansl[now],l1,i^1);
	}
}
signed main(void) {
    n=read(),m=read(); 
    for(re int i=1,x,y;i<n;i++) { x=read(); y=read(); add(x,y); add(y,x); }
    for(re int i=1,x;i<=m;i++) { x=read(); w[x]=1; }
    son[0]=1ll; dfs1(1,0,0,0); 
   	int sc=qpow((1ll-f[1].c+mol)%mol,mol-2); f[1].c=0ll;
   	(f[1].a*=sc)%=mol; (f[1].b*=sc)%=mol; (f[1].d*=sc)%=mol;
   	dfs2(1,0,0,0);
   	for(re int i=1;i<=n;i++) printf("%lld\n",ansl[i]);
}
posted @ 2021-08-25 07:33  zJx-Lm  阅读(95)  评论(1编辑  收藏  举报