日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

【PKUWC2018】Minimax【线段树合并】

發布時間:2023/12/3 编程问答 31 豆豆
生活随笔 收集整理的這篇文章主要介紹了 【PKUWC2018】Minimax【线段树合并】 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

題意:給定一棵nnn個點的二叉樹,葉子的權值輸入給定且互不相同,非葉子結點iii的權值有pip_ipi?的概率為兒子結點權值最大值,1?pi1-p_i1?pi?的概率為最小值。求根結點取每種值的概率。模998244353998244353998244353

n≤3×105n\leq 3\times 10^5n3×105

這都能線段樹合并……覺了
f(u,x)f(u,x)f(u,x)uuu點值為xxx的概率,l,rl,rl,r為它的左右兒子

容易寫出

f(u,x)=px[f(l,x)∑i=1x?1f(r,i)+f(r,x)∑i=1x?1f(l,i)]+(1?px)[f(l,x)∑i=x+1mf(r,i)+f(r,x)∑i=x+1mf(l,i)]f(u,x)=p_x[f(l,x)\sum_{i=1}^{x-1}f(r,i)+f(r,x)\sum_{i=1}^{x-1}f(l,i)]+(1-p_x)[f(l,x)\sum_{i=x+1}^mf(r,i)+f(r,x)\sum_{i=x+1}^mf(l,i)]f(u,x)=px?[f(l,x)i=1x?1?f(r,i)+f(r,x)i=1x?1?f(l,i)]+(1?px?)[f(l,x)i=x+1m?f(r,i)+f(r,x)i=x+1m?f(l,i)]

考慮線段樹合并

設當前合并的區間是[L,R][L,R][L,R],在遞歸的時候順便維護兩個線段樹結點[1,L?1][1,L-1][1,L?1][R+1,m][R+1,m][R+1,m]的和,乘到f(l,x)f(l,x)f(l,x)f(r,x)f(r,x)f(r,x)上面,維護一個乘法標記。

文字不太好講清楚,建議直接看代碼。

復雜度O(nlog?n)O(n\log n)O(nlogn)

#include <iostream> #include <cstdio> #include <cstring> #include <cctype> #include <algorithm> #define MAXN 300005 using namespace std; inline int read() {int ans=0;char c=getchar();while (!isdigit(c)) c=getchar();while (isdigit(c)) ans=(ans<<3)+(ans<<1)+(c^48),c=getchar();return ans; } const int MOD=998244353; typedef long long ll; inline int qpow(int a,int p) {int ans=1;while (p){if (p&1) ans=(ll)ans*a%MOD;a=(ll)a*a%MOD;p>>=1;}return ans; } namespace SGT {int ch[MAXN<<5][2],sum[MAXN<<5],mul[MAXN<<5],cnt;inline void update(int x){sum[x]=(sum[ch[x][0]]+sum[ch[x][1]])%MOD;}inline void pushmul(int x,int v){sum[x]=(ll)sum[x]*v%MOD,mul[x]=(ll)mul[x]*v%MOD;}inline void pushdown(int x){if (mul[x]!=1){pushmul(ch[x][0],mul[x]),pushmul(ch[x][1],mul[x]);mul[x]=1;}}inline int newnode(){return ++cnt,sum[cnt]=mul[cnt]=1,cnt;}void insert(int& x,int l,int r,int k){x=newnode();if (l==r) return;int mid=(l+r)>>1;if (k<=mid) insert(ch[x][0],l,mid,k);else insert(ch[x][1],mid+1,r,k);}int merge(int x,int y,int l,int r,int xmul,int ymul,int v){if (!x&&!y) return 0;if (!x) return pushmul(y,ymul),y;if (!y) return pushmul(x,xmul),x;int mid=(l+r)>>1;pushdown(x),pushdown(y);int xl=sum[ch[x][0]],xr=sum[ch[x][1]],yl=sum[ch[y][0]],yr=sum[ch[y][1]];ch[x][0]=merge(ch[x][0],ch[y][0],l,mid,(xmul+(MOD+1ll-v)*yr)%MOD,(ymul+(MOD+1ll-v)*xr)%MOD,v);ch[x][1]=merge(ch[x][1],ch[y][1],mid+1,r,(xmul+(ll)v*yl)%MOD,(ymul+(ll)v*xl)%MOD,v);return update(x),x;}void getans(int x,int l,int r,int* &ans){if (l==r) return (void)(*(ans++)=sum[x]);pushdown(x);int mid=(l+r)>>1;getans(ch[x][0],l,mid,ans),getans(ch[x][1],mid+1,r,ans);} } using SGT::insert; using SGT::merge; using SGT::getans; int rt[MAXN],ch[MAXN][2],p[MAXN],v[MAXN],m; void dfs(int u) {if (!ch[u][0]) return insert(rt[u],1,m,p[u]);dfs(ch[u][0]);if (!ch[u][1]) return (void)(rt[u]=rt[ch[u][0]]);dfs(ch[u][1]);rt[u]=merge(rt[ch[u][0]],rt[ch[u][1]],1,m,0,0,p[u]); } int ans[MAXN]; int main() {int n=read();for (int i=1;i<=n;i++){int f=read();if (!f) continue;if (!ch[f][0]) ch[f][0]=i;else ch[f][1]=i;}int t=qpow(10000,MOD-2);for (int i=1;i<=n;i++){p[i]=read();if (ch[i][0]) p[i]=(ll)p[i]*t%MOD;else v[++m]=p[i];}sort(v+1,v+m+1);for (int i=1;i<=n;i++)if (!ch[i][0])p[i]=lower_bound(v+1,v+m+1,p[i])-v;dfs(1);int* p=ans+1;getans(rt[1],1,m,p);int res=0;for (int i=1;i<=m;i++) res=(res+(ll)i*v[i]%MOD*ans[i]%MOD*ans[i])%MOD;printf("%d\n",res);return 0; }

總結

以上是生活随笔為你收集整理的【PKUWC2018】Minimax【线段树合并】的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。