Mushroom Gnomes(离散化+线段树)

215 阅读1分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第25天,点击查看活动详情

题目链接:codeforces.com/problemset/…

题目中文翻译:

n个电线杆,m棵小草,每个电线杆给位置a[i],高度h[i],倒向左边的概率L[i],倒向右边的概率R[i],倒向左边会覆盖[a[i]-h[i],a[i]-1].倒向右边会覆盖[a[i]+1,a[i]+h[i]],每棵小草都有自己的位置b[j],以及价值z[j],如果小草被一个电线杆或者多个电线杆砸到那么它的价值就为0,问最终所有小草价值的期望和。

Input

第一行n,m(1<=n<=100000,1<=m<=10000)

接下来n行,每行四个整数,a[i],h[i],L[i],Ri

接下来m行,每行两个整数,b[j],zj

任意数量的电线杆和小草可以在一个点上生长。

输入输出见题目。

分析:小草的期望和就是最后小草存活的概率乘以小草的价值然后加起来就好,现在关键就是求小草存活的概率了,小草怎么样才能存活呢?是不是所有电线杆都不砸到他?也就是所有电线杆不砸到他的概率的乘积,到这问题就变成了一个区间维护乘积的一个线段树题目了,注意这题的数据范围,不难发现需要进行离散化,先说一下这道题目容易出错的点吧:第一个就是可以有多颗小草在同一个地方,我们直接看成一颗小草就行,价值就是在这个点的所有小草的价值和,还有一个就是电线杆可以和小草在同一个位置,且小草不会被压死,剩下就没什么了,上代码:

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<queue>
#include<vector>
using namespace std;
const int N=3e6+10;
int l[N],r[N];
double lazy[N],sum[N],a[N];
vector<int> alls;
struct Node{
	int pos,h;
	double pl,pr;
}st[N];
struct node{
	int pos;
	double w;
}pt[N];
int find(int x)
{
	return lower_bound(alls.begin(),alls.end(),x)-alls.begin()+1;
}
void pushup(int id)
{
	sum[id]=sum[id<<1]+sum[id<<1|1];
}
void pushdown(int id)
{
	//注意,乘积的单位元是1 
	if(lazy[id]!=1)
	{
		sum[id<<1]*=lazy[id];
		sum[id<<1|1]*=lazy[id];
		lazy[id<<1]*=lazy[id];
		lazy[id<<1|1]*=lazy[id];
		lazy[id]=1;
	}
}
void build(int id,int L,int R)
{
	l[id]=L;r[id]=R;lazy[id]=1;sum[id]=0;
	if(L==R)
	{
		sum[id]+=a[L];
		return ;
	}
	int mid=L+R>>1;
	build(id<<1,L,mid);
	build(id<<1|1,mid+1,R);
	pushup(id);
}
void update_interval(int id,int L,int R,double val)
{
	if(l[id]>R||r[id]<L) return ;
	if(l[id]>=L&&r[id]<=R)
	{
		lazy[id]*=val;
		sum[id]*=val;
		return ;
	}
	pushdown(id);
	update_interval(id<<1,L,R,val);
	update_interval(id<<1|1,L,R,val);
	pushup(id);
}
 
double query_interval(int id,int L,int R)
{
	if(l[id]>R||r[id]<L) return 0;
	if(l[id]>=L&&r[id]<=R) return sum[id];
	pushdown(id);
	return query_interval(id<<1,L,R)+query_interval(id<<1|1,L,R);
}
int main()
{
	int n,m;
	cin>>n>>m;
	for(int i=1;i<=n;i++)
	{
		scanf("%d%d%lf%lf",&st[i].pos,&st[i].h,&st[i].pl,&st[i].pr);
		alls.push_back(st[i].pos-1);
		alls.push_back(st[i].pos+1);
		alls.push_back(st[i].pos-st[i].h);
		alls.push_back(st[i].pos+st[i].h);
	}
	for(int i=1;i<=m;i++)
	{
		scanf("%d%lf",&pt[i].pos,&pt[i].w);
		alls.push_back(pt[i].pos);
	}
	sort(alls.begin(),alls.end());//离散化 
	alls.erase(unique(alls.begin(),alls.end()),alls.end());
	for(int i=1;i<=m;i++)
		a[find(pt[i].pos)]+=pt[i].w;//注意一个位置有多个草的情况
	build(1,1,alls.size());
	for(int i=1;i<=n;i++)
	{
		update_interval(1,find(st[i].pos-st[i].h),find(st[i].pos-1),1-st[i].pl/100);//更新电线杆左侧被压到的区域 
		update_interval(1,find(st[i].pos+1),find(st[i].pos+st[i].h),1-st[i].pr/100);//更新电线杆右侧被压到的区域 
	}
	printf("%.10lf",query_interval(1,1,alls.size()));
	return 0;
}