• 吃粮


    img

    img

    题目大意

    给定一棵树,(1) 号点为根,每个点有点权,从某一点出发每次等概率地到达相邻的点中的一个,到叶子节点位置(保证根节点度数不为(1))位置

    支持修改点权,求从根出发形成的路径的点权和期望。

    题解

    (F_x) 表示从 (x) 出发的答案,(V_x)(x) 点权,(D_x)(x) 的度数那么显然

    [F_x=V_x+sum frac{F_{to}}{D_X} (D_x>1)\ F_x=V_x (D_x=1) ]

    由于转移带环,似乎只能消元,所以你可以暴力 (O(n^3Q)) 获得 (20) 分的好成绩

    仔细观察消元的过程,你会发现你可以把 (F_x) 中的 (V_k) 系数表示出来,这样就可以 (O(n^3+nQ)) 获得 (40)

    注意到它是一棵树,意味着 (F_x) 只会出现在相邻 点上,有一个很巧妙的方法

    (p=x)的父节点 ,我们可以假设 (F_p) 已知。

    不妨设(F_x=K_xF_p+B_x)

    那么对于叶子节点,显然有(K_x=0,B_x=V_X​)

    然后考虑展开非叶子结点的式子。

    [F_x=V_x+sum frac{F_{to}}{D_X} (D_x>1)\ D_xF_x=D_xV_x+sum F_{son}+F_p\ D_xF_x=D_xV_x+sum (K_{son}F_x+B_{son})+F_p\ (D_x-sum K_{son})F_x=sum B_{son}+D_xV_x+F_p\ K_x=frac{1}{D_x-sum K_{son}}\ B_x=frac{sum B_{son}+D_xV_x}{D_x-sum K_{son}}\ ]

    这样可以 (O(n)) 递推出 (B_1) 即为答案,可以 (O(nQ)) 获得 (60)

    仔细观察式子,设 (G_x=D_x-sum K_{son}) 不难发现 (V_x) 的贡献是 (frac{D_x}{prodlimits_{kin{Anc_x}}G_k})

    其中 (Anc_x) 表示 (x)(x) 的祖先。

    这样即可 (O(nlog n+Q)) 获得满分。

    #include<bits/stdc++.h>
    #define debug(x) cerr<<#x<<" = "<<x
    #define sp <<"   "
    #define el <<endl
    #define fgx cerr<<"  ---------------------------  "<<endl
    #define pii pair<int,int>
    #define mp make_pair
    #define LL long long
    #define M 100020
    #define mod 998244353
    using namespace std;
    int read(){
    	int nm=0,fh=1; char cw=getchar();
    	for(;!isdigit(cw);cw=getchar()) if(cw=='-') fh=-fh;
    	for(;isdigit(cw);cw=getchar()) nm=nm*10+(cw-'0');
    	return nm*fh;
    }
    inline int mul(int x,int y){return (LL)x*(LL)y%mod;}
    inline int add(int x,int y){x+=y;return (x>=mod)?(x-mod):x;}
    inline int mns(int x,int y){x-=y;return (x<0)?(x+mod):x;}
    inline int upd(int &x,int y){x+=y;(x>=mod)?(x-=mod):0;}
    int n,m,fs[M],nt[M<<2],to[M<<2],val[M],D[M],tmp,B[M],K[M],ans;
    #define link(a,b) nt[tmp]=fs[a],fs[a]=tmp,D[to[tmp++]=b]++
    inline int qpow(int x,int sq){
    	int res=1;
    	for(;sq;sq>>=1,x=mul(x,x)) if(sq&1) res=mul(res,x);
    	return res;
    }
    void dfs1(int x,int p){
    	if(D[x]==1){B[x]=val[x],K[x]=0;return;}
    	for(int i=fs[x],v;i!=-1;i=nt[i]) if((v=to[i])^p)
    		dfs1(v,x),upd(K[x],K[v]),upd(B[x],B[v]);
    	int dw=qpow(mns(D[x],K[x]),mod-2); K[x]=dw;
    	B[x]=mul(add(mul(D[x],val[x]),B[x]),dw); 
    }
    void dfs2(int x,int p){
    	if(D[x]==1) K[x]=1; K[x]=mul(K[x],K[p]);
    	for(int i=fs[x];i!=-1;i=nt[i]) if(to[i]^p) dfs2(to[i],x); 		K[x]=mul(K[x],D[x]);
    }
    int main(){
    	n=read(),memset(fs,-1,sizeof(fs));
    	for(int i=1;i<=n;i++) val[i]=read();
    	for(int i=1,x,y;i<n;i++) x=read(),y=read(),link(x,y),link(y,x);
    	dfs1(1,0),ans=B[K[0]=1],dfs2(1,0),printf("%d
    ",ans);
    	for(int Cas=read(),dt,ps,k;Cas;--Cas){
    		ps=read(),dt=mns(k=read(),val[ps]),val[ps]=k;
    		upd(ans,mul(K[ps],dt)),printf("%d
    ",ans);
    	} return 0;
    }
    
  • 相关阅读:
    Elastic Search查询DSL的生成器
    清除Git仓库未托管的文件
    在Asp.net Core 中配置HTTPS支持
    VUE3的新构建工具Vite使用简介
    文档驱动 —— 表单组件(六):基于AntDV的Form表单的封装,目标还是不写代码
    文档驱动 —— 查询组件:使用 vue3.0 的新特性,重构代码
    文档驱动 —— 表单组件(五):基于Ant Design Vue 的表单控件的demo,再也不需要写代码了。
    文档驱动 —— 表单组件(四):基于Ant Design Vue封装一些表单域控件
    文档驱动 —— 表单组件(三):基于原生html的表单组件demo
    文档驱动 —— 表单组件(二):meta生成器,告别书写代码
  • 原文地址:https://www.cnblogs.com/OYJason/p/10284267.html
Copyright © 2020-2023  润新知