CF895 E - Eyes Closed 线段树维护乘法和加法

如果时暴力做的话:

对l1,r1区间内的数,每个数有1/(r1-l1+1)的概率被替换,被替换成的数的期望为sum(l2,r2)/(r2-l2+1)  

所以l1,r1区间内一个数 a[x]=1/(r1-l1+1)*sum(l2,r2)/(r2-l2+1)  +(r1-l1)/(r1-l1+1) * a[x];

化简为:  a[x]= a[x]*k + b;

k,b是常数。

然后用线段树维护搞搞就行

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
//typedef __int128 LL;
//typedef unsigned long long ull;
//#define F first
//#define S second
typedef long double ld;
typedef pair<int,int> pii;
typedef pair<ll,ll> pll;
typedef pair<ld,ld> pdd;
const ld PI=acos(-1);
const ld eps=1e-9;
//unordered_map<int,int>mp;
#define ls (o<<1)
#define rs (o<<1|1)
#define pb push_back
//#define a(i,j) a[(i)*(m+2)+(j)]  //m是矩阵的列数
//pop_back()
const int seed=131;
const int M = 1e5+7;
/*
int head[M],cnt;
void init(){cnt=0,memset(head,0,sizeof(head));}
struct EDGE{int to,nxt,val;}ee[M*2];
void add(int x,int y,int z){ee[++cnt].nxt=head[x],ee[cnt].to=y,ee[cnt].val=z,head[x]=cnt;}
*/
double a[M];
double sm[M<<2];//维护区间和 
double mul[M<<2];//乘法标记
double add[M<<2];//加法标记
void bd(int o,int l,int r)
{
	mul[o]=1,add[o]=0;
	if(l==r)
	{
		mul[o]=1;
		add[o]=0;
		sm[o]=a[l];
		return ;
	}
	int m=(l+r)/2;
	bd(ls,l,m);
	bd(rs,m+1,r);
	sm[o]=sm[ls]+sm[rs];
} 
void pd(int o,int l,int r)
{
	int m=(l+r)/2;
//	if(mul[o]==1&&add[o]==0)
	{
		mul[ls]*=mul[o],mul[rs]*=mul[o];
		add[ls]*=mul[o],add[rs]*=mul[o];
		add[ls]+=add[o],add[rs]+=add[o];
		sm[ls]=sm[ls]*mul[o]+add[o]*(m-l+1);
		sm[rs]=sm[rs]*mul[o]+add[o]*(r-m);
		mul[o]=1;add[o]=0;
	}
}
void up(int o,int l,int r,int x,int y,double k,double b)//x-y区间内先乘k再加b 
{
	if(x<=l&&r<=y)
	{
		mul[o]*=k,add[o]*=k,add[o]+=b;
		sm[o]=sm[o]*k+b*(r-l+1);
		return ;
	}
	pd(o,l,r);
	int m=(l+r)/2;
	if(x<=m)up(ls,l,m,x,y,k,b);
	if(y>m)up(rs,m+1,r,x,y,k,b);
	sm[o]=sm[ls]+sm[rs];
}
double qu(int o,int l,int r,int x,int y)
{
	if(x<=l&&r<=y)
	{
		return sm[o];
	}
	int m=(l+r)/2;
	pd(o,l,r);
	double ans=0;
	if(x<=m)ans+=qu(ls,l,m,x,y);
	if(y>m)ans+=qu(rs,m+1,r,x,y);
	return ans;
}
int main()
{
  	int n,q;
  	scanf("%d%d",&n,&q);
  	for(int i=1;i<=n;i++)scanf("%lf",&a[i]);
  	bd(1,1,n);
  	while(q--)
  	{
  	//	cout<<"okkk"<<endl;
  		int opt,l1,r1,l2,r2;
  		double sm1=0,sm2=0,k,b;
  		scanf("%d",&opt);
  		if(opt==1)
	  	{
	  		scanf("%d%d%d%d",&l1,&r1,&l2,&r2);
	  		sm1=qu(1,1,n,l1,r1);sm2=qu(1,1,n,l2,r2);
	  		k=1.0*(r1-l1)/(r1-l1+1);
			b=sm2/(r2-l2+1);
			b/=(r1-l1+1);
			up(1,1,n,l1,r1,k,b);//l1,r1区间的数先乘k再加b 
	  	//	cout<<k<<" "<<b;
			k=1.0*(r2-l2)/(r2-l2+1);b=sm1/(r1-l1+1);
			b/=(r2-l2+1);
			up(1,1,n,l2,r2,k,b);
		//	cout<<"  ----"<<k<<" "<<b<<endl;
		}
		else
		{
			scanf("%d%d",&l1,&r1);
			double tp=qu(1,1,n,l1,r1);
			printf("%.7f\n",tp);
		}
	}
	return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值