LuoguP3924 康娜的線段樹 期望+線段樹
阿新 • • 發佈:2020-07-09
根據期望的定義,我們可以求出所有情況之和再除以情況數量.
如果長度滿足 $n=2^k$,線段樹上一個節點新加 $v$ 的話 $v$ 的貢獻就是 $v \times si[x]$,si[x] 即子樹下葉節點個數.
如果長度不滿足上述條件,由於線段樹是完全二叉樹結構,我們可以強制讓深度小於最大深度的葉節點多一個貢獻。
如果單點修改,該點的貢獻就是葉節點到根節點所有節點 $si[x]$ 之和乘以 $v$,然後區間修改的話可以用字首和來算區間的貢獻.
時間複雜度為 $O(4n)+O(n)=O(n)$.
code:
#include <cstdio> #include <algorithm> #include <cstring> #define ll long long #define N 1000009 #define lson now<<1 #define rson now<<1|1 #define setIO(s) freopen(s".in","r",stdin) using namespace std; ll Q; ll sum[N],val[N<<2]; int dep[N<<2],si[N<<2],a[N],n,m,maxdep; void build(int l,int r,int now) { dep[now]=dep[now>>1]+1; if(l==r) { maxdep=max(maxdep,dep[now]); if(dep[now]<maxdep) { si[now]=2; } else si[now]=1; return; } int mid=(l+r)>>1; build(l,mid,lson),build(mid+1,r,rson); si[now]=si[lson]+si[rson]; } void dfs2(int l,int r,int now) { val[now]=si[now]+val[now>>1]; if(l==r) { sum[l]=val[now]; return; } int mid=(l+r)>>1; dfs2(l,mid,lson),dfs2(mid+1,r,rson); } int main() { // setIO("input"); scanf("%d%d%lld",&n,&m,&Q); build(1,n,1); dfs2(1,n,1); for(int i=1;i<=n;++i) sum[i]+=sum[i-1]; ll ans=0; for(int i=1;i<=n;++i) scanf("%d",&a[i]),ans+=(sum[i]-sum[i-1])*a[i]; int x,y,z; ll dn=si[1]; ll gcd=__gcd(dn,Q); dn/=gcd,Q/=gcd; for(int i=1;i<=m;++i) { scanf("%d%d%d",&x,&y,&z); ans+=(sum[y]-sum[x-1])*1ll*z; printf("%lld\n",ans/dn*Q); } return 0; }