Cutting Bamboos 主席树+二分 牛客

链接:https://ac.nowcoder.com/acm/contest/889/H
题面:
There are n bamboos arranged in a line. The i-th bamboo from the left has height h i h_{i} hi.
You are given q queries of the type (l, r, x, y). For each query (l, r, x, y) we consider only the l-th to r-th bamboo inclusive. We want to make y horizontal cuts through these bamboos, such that after each cut, the total length of bamboo cut is the same, and after all y cuts there is no bamboo left. For example, if there are 3 bamboos of height 3, 4, 5 respectively and y = 4. The first cut should be at height 3, after which the heights of the bamboos are 3, 3, 3 respectively and the total amount of bamboo cut is 0 + 1 + 2 = 3. Then, the next 3 cuts should be at height 2, 1, 0 respectively. You want to find out what is the height the x-th cut is performed.
Note that after each query, the bamboos are not actually cut, so the heights of the bamboos remain constant after each query.
题意: 给你一排竹子,每次砍一个区间的竹子,将该区间在恰好砍y次以后竹子高度为0,要求每次砍掉的竹子总长度相等,问第x次砍的竹子高度是多少?
每一次询问过后,竹子都会恢复原来的高度
思路: 我们可以计算得出到第x次时,总共砍下的总长度,所以我们可以二分高度,用主席树得到在区间范围内,低于二分高度的竹子长度与数量,从而确定第x次砍竹子的高度

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=2e5+5;
const int M=1e5;
const double eps=1e-8;
int rt[N],ls[N*32],rs[N*32],sum[N*32];
int cnt;
ll s[N],val[N*32];
void update(int &now,int pre,int l,int r,int k)
{
	now=++cnt;
	sum[now]=sum[pre]+1;
	val[now]=val[pre]+k;
	ls[now]=ls[pre];
	rs[now]=rs[pre];
	if(l==r)
		return ;
	int mid=(l+r)>>1;
	if(k<=mid)
		update(ls[now],ls[pre],l,mid,k);
	else
		update(rs[now],rs[pre],mid+1,r,k);
}
ll h,sh;

void query(int now,int pre,int l,int r,int x)
{
	if(l>x)
		return ;
	if(r<=x)
	{
		sh+=val[now]-val[pre];
		h+=sum[now]-sum[pre];
		return ;
	}
	int mid=(l+r)>>1;
	query(ls[now],ls[pre],l,mid,x);
	query(rs[now],rs[pre],mid+1,r,x);
}

int main()
{
	int n,m;
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++)
	{
		int x;
		scanf("%d",&x);
		s[i]=s[i-1]+x;
		update(rt[i],rt[i-1],1,M,x);
	}
	while(m--)
	{
		int l,r,x,y;
		scanf("%d%d%d%d",&l,&r,&x,&y);
		double l1=0,r1=100000.0;
		while(r1-l1>eps)
		{
			h=sh=0;
			double mid=(l1+r1)/2;
			query(rt[r],rt[l-1],1,M,(int)mid);
			h=(r-l+1)-h;
			double tmp=mid*h+sh;
			if(tmp-(s[r]-s[l-1])*1.0/y*(y-x)>eps)
				r1=mid;
			else
				l1=mid;
		}
		printf("%.6f\n",l1);
	}
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值