题解 [ABC332F] Random Update Query

【洛谷博客】

相对于过往比赛的 F 应该算正常难度,但是这个概率与期望相对于 E 的状态压缩动态规划要略简单一点。

题意

题意翻译很清楚。

分析

根据期望的定义\(EX=\sum x_ip_i\)

对于第 \(i\) 个数,第 \(j\) 次操作,对于任意的 \(L_j \le i \le R_j\),那么这一次操作选中一个数赋值的概率是 \(P_j=\dfrac{1}{R_j-L_j+1}\),所以 \(E_i = E_i(1-P_j)+X_jP_j\)

关注到这是一个区间加乘的操作,所以直接复制 P2023 [AHOI2009] 维护序列 的线段树模板就行。

代码

//the code is from chenjh
#include<bits/stdc++.h>
#define M(s) (s)%=p 
using namespace std;
typedef long long LL;
const LL p=998244353;
int n,m;
LL qpow(LL a,LL b){
	LL ret=1;
	for(;b;b>>=1,a=a*a%p)if(b&1)ret=ret*a%p;
	return ret%p;
}
LL a[200002],sum[800008];
LL add[800008],mul[800008];
void build(int rt,int l,int r){
	if(l==r){
		sum[rt]=a[l];
		mul[rt]=1;
		return;
	}
	int m=(l+r)/2;
	build(rt*2,l,m);
	build(rt*2+1,m+1,r);
	sum[rt]=sum[rt*2]+sum[rt*2+1];
	mul[rt]=mul[rt*2]=mul[rt*2+1]=1;
}
void push_down(int rt,int l,int r){
	int m=(l+r)/2;
	sum[rt*2]*=mul[rt];M(sum[rt*2]);
	sum[rt*2]+=add[rt]*(m-l+1);M(sum[rt*2]);
	add[rt*2]*=mul[rt];M(add[rt*2]);
	add[rt*2]+=add[rt];M(add[rt*2]);
	mul[rt*2]*=mul[rt];M(mul[rt*2]);
	sum[rt*2+1]*=mul[rt];M(sum[rt*2+1]);
	sum[rt*2+1]+=add[rt]*(r-m);M(sum[rt*2+1]);
	add[rt*2+1]*=mul[rt];M(add[rt*2+1]);
	add[rt*2+1]+=add[rt];M(add[rt*2+1]);
	mul[rt*2+1]*=mul[rt];M(mul[rt*2+1]);
	mul[rt]=1,add[rt]=0; 
}
void update(int rt,int l,int r,int L,int R,LL val,int op){
	if(L<=l && r<=R){
		if(op==0){
			sum[rt]+=val*(r-l+1);M(sum[rt]);
			add[rt]+=val;M(add[rt]);
		}
		else{
			sum[rt]*=val;M(sum[rt]);
			add[rt]*=val;M(add[rt]);
			mul[rt]*=val;M(mul[rt]);
		}
		return;
	}
	push_down(rt,l,r);
	int m=(l+r)/2;
	if(m>=L) update(rt*2,l,m,L,R,val,op);
	if(m<R) update(rt*2+1,m+1,r,L,R,val,op);
	sum[rt]=sum[rt*2]%p+sum[rt*2+1]%p;
	sum[rt]%=p;
}
LL query(int rt,int l,int r,int L,int R){
	if(L<=l && r<=R) return sum[rt];
	push_down(rt,l,r);
	int m=(l+r)/2;
	LL ret=0;
	if(L<=m){ret+=query(rt*2,l,m,L,R);M(ret);}
	if(m<R){ret+=query(rt*2+1,m+1,r,L,R);M(ret);}
	return ret;
}
int main(){
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++) scanf("%lld",&a[i]);
	build(1,1,n);
	for(int l,r,x;m--;){
		scanf("%d%d%d",&l,&r,&x);
		int len=r-l+1,inv=qpow(len,p-2);//求出 1/(r-l+1)。
		update(1,1,n,l,r,(LL)(len-1)*inv%p,1);//区间乘。
		update(1,1,n,l,r,(LL)x*inv%p,0);//区间加。
	}
	for(int i=1;i<=n;i++) printf("%lld ",query(1,1,n,i,i));
	return 0;
}
posted @ 2024-01-20 11:46  Chen_Jinhui  阅读(20)  评论(0)    收藏  举报