51nod-动物与游戏【树链剖分,线段树】

1|0正题

题目链接:http://www.51nod.com/Contest/Problem.html#contestProblemId=3957


1|1题目大意

n个点的一棵树,第i个节点上的动物有ai100的概率加入,每个加入的动物都会每秒向父节点移动。

对于第i只动物,如果它到达一个节点时还没有其他动物比他早来过,那么它的权值加一。

现在对于每一只动物求它参加的话它的期望权值。

1n105,1ai100


1|2解题思路

考虑一个动物x能拿到一个节点y的权值的条件,也就是y的子树中深度比x小的动物都不参赛的概率。

也就是对于一个动物x,动物z能对它产生影响首先要求depz<depx,并且只会从LCA(x,z)处向上开始产生影响。

发现一个特点是从LCA处产生影响,这就和[LNOI2014]LCA很像了,我们对于会产生影响的z把它到根节点上的路径都修改了,然后直接询问x到根节点路径上的权值就好了。

至于depz<depx这个条件我们把所有节点按照深度从小到大排序然后处理即可。

时间复杂度:O(nlog2n)


1|3code

#include<cstdio> #include<cstring> #include<algorithm> #define ll long long using namespace std; const ll N=1e5+10,P=998244353; struct node{ ll to,next; }a[N<<1]; ll n,tot,cnt,inv100,fa[N],ls[N],c[N],p[N],ans[N]; ll siz[N],dep[N],son[N],top[N],seq[N],id[N]; ll power(ll x,ll b){ ll ans=1; while(b){ if(b&1)ans=ans*x%P; x=x*x%P;b>>=1; } return ans; } void addl(ll x,ll y){ a[++tot].to=y; a[tot].next=ls[x]; ls[x]=tot;return; } struct Seq_Tree{ ll w[N<<2],lazy[N<<2]; void Downdata(ll x){ if(lazy[x]==1)return; w[x*2]=w[x*2]*lazy[x]%P; w[x*2+1]=w[x*2+1]*lazy[x]%P; lazy[x*2]=lazy[x*2]*lazy[x]%P; lazy[x*2+1]=lazy[x*2+1]*lazy[x]%P; lazy[x]=1;return; } void Build(ll x,ll L,ll R){ lazy[x]=1; if(L==R){w[x]=1;return;} ll mid=(L+R)>>1; Build(x*2,L,mid); Build(x*2+1,mid+1,R); w[x]=w[x*2]+w[x*2+1]; } void Change(ll x,ll L,ll R,ll l,ll r,ll val){ if(L==l&&R==r){w[x]=w[x]*val%P;lazy[x]=lazy[x]*val%P;return;} ll mid=(L+R)>>1;Downdata(x); if(r<=mid)Change(x*2,L,mid,l,r,val); else if(l>mid)Change(x*2+1,mid+1,R,l,r,val); else Change(x*2,L,mid,l,mid,val),Change(x*2+1,mid+1,R,mid+1,r,val); w[x]=(w[x*2]+w[x*2+1])%P; } ll Ask(ll x,ll L,ll R,ll l,ll r){ if(L==l&&R==r)return w[x]; ll mid=(L+R)>>1;Downdata(x); if(r<=mid)return Ask(x*2,L,mid,l,r); if(l>mid)return Ask(x*2+1,mid+1,R,l,r); return (Ask(x*2,L,mid,l,mid)+Ask(x*2+1,mid+1,R,mid+1,r))%P; } }T; void dfs1(ll x){ siz[x]=1;dep[x]=dep[fa[x]]+1; for(ll i=ls[x];i;i=a[i].next){ ll y=a[i].to; if(y==fa[x])continue; fa[y]=x;dfs1(y); siz[x]+=siz[y]; if(siz[y]>siz[son[x]])son[x]=y; } return; } void dfs2(ll x){ id[x]=++cnt;seq[cnt]=x; if(son[x]){ top[son[x]]=top[x]; dfs2(son[x]); } for(ll i=ls[x];i;i=a[i].next){ ll y=a[i].to; if(y==son[x]||y==fa[x]) continue; top[y]=y;dfs2(y); } } void Updata(ll x,ll val){ while(x){ T.Change(1,1,n,id[top[x]],id[x],val); x=fa[top[x]]; } return; } ll Ask(ll x){ ll ans=0; while(x){ (ans+=T.Ask(1,1,n,id[top[x]],id[x]))%=P; x=fa[top[x]]; } return ans; } bool cmp(ll x,ll y) {return dep[x]<dep[y];} signed main() { inv100=power(100,P-2); scanf("%lld",&n); for(ll i=1;i<=n;i++){ scanf("%lld",&c[i]);p[i]=i; c[i]=(100-c[i])*inv100%P; } for(ll i=1;i<n;i++){ ll x,y; scanf("%lld%lld",&x,&y); addl(x,y);addl(y,x); } dfs1(1);top[1]=1;dfs2(1); sort(p+1,p+1+n,cmp); T.Build(1,1,n); for(ll i=2,l=1;i<=n+1;i++){ if(dep[p[i]]!=dep[p[i-1]]){ ll r=i-1; for(ll j=l;j<=r;j++) ans[p[j]]=Ask(p[j]); for(ll j=l;j<=r;j++) Updata(p[j],c[p[j]]); l=i; } } for(ll i=1;i<=n;i++) printf("%lld\n",ans[i]); return 0; }

__EOF__

本文作者QuantAsk
本文链接https://www.cnblogs.com/QuantAsk/p/15735475.html
关于博主:退役OIer,GD划水选手
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   QuantAsk  阅读(46)  评论(0编辑  收藏  举报
编辑推荐:
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 张高兴的大模型开发实战:(一)使用 Selenium 进行网页爬虫
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
点击右上角即可分享
微信分享提示