题意:
给定区间, 切y次将区间内的树全切完,每次切掉的所有和相同
切每次都是高度为h的横刀(区间高于h的值全部变为h),求第x次切的高度
解题思路:
第x次切的高度不知道,但是第1 - x次一共切掉的高度和剩下的高度可以O1计算而出
可持久化权值树记录cnt和sum
二分枚举一个高度,使得区间内所有高于此高度的权值变为此高度, 剩下的和刚才O1算出的比较即可
在权值树上查询等同于找到一个满足题意得最左值,将该值右侧的所以值加起来即可计算剩余值
代码:
/*
Zeolim - An AC a day keeps the bug away
*/
//#pragma GCC optimize(2)
//#pragma GCC ("-W1,--stack=128000000")
#include <bits/stdc++.h>
using namespace std;
#define mp(x, y) make_pair(x, y)
#define fr(x, y, z) for(int x = y; x < z; ++x)
#define pb(x) push_back(x)
#define mem(x, y) memset(x, y, sizeof(x))
typedef long long ll;
typedef unsigned long long ull;
typedef long double ld;
typedef std::pair <int, int> pii;
typedef std::vector <int> vi;
//typedef __int128 ill;
const ld PI = acos(-1.0);
const ld E = exp(1.0);
const ll INF = 0x3f3f3f3f3f3f3f3f;
const ll MOD = 386910137;
const ull P = 13331;
const int MAXN = 1e6 + 10;
struct zxt
{
int root[MAXN * 20], tot = 0;
struct node { int ls, rs; ll cnt, sum;}t[MAXN];
void update(int l, int r, int &now, int lst, int pos)
{
now = ++tot, t[now] = t[lst];
++t[now].cnt, t[now].sum += pos;
if(l == r) { return ; }
int mid = (l + r) >> 1;
if(pos <= mid) update(l, mid, t[now].ls, t[lst].ls, pos);
else update(mid + 1, r, t[now].rs, t[lst].rs, pos);
}
ll x, y;
void query(int l, int r, int now, int lst, ld pos)
{
if(l == r)
{
x += ( t[now].cnt - t[lst].cnt);
y += ( t[now].sum - t[lst].sum);
return ;
}
ll mid = (l + r) >> 1;
if(pos <= ld(mid) )
{
x += ( t[t[now].rs].cnt - t[t[lst].rs].cnt);
y += ( t[t[now].rs].sum - t[t[lst].rs].sum);
query(l, mid, t[now].ls, t[lst].ls, pos);
}
else query(mid + 1, r, t[now].rs, t[lst].rs, pos);
}
}T;
ll arr[MAXN] = {0};
ll l, r, x, y, rsum;
ld nowsum;
int n, q;
bool check(ld mid)
{
T.x = 0, T.y = 0;
T.query(1, 100000, T.root[r], T.root[l - 1], mid);
return (T.x * mid + (rsum - T.y) < nowsum);
}
int main()
{
ios::sync_with_stdio(0);
cin.tie(0); cout.tie(0);
cin >> n >> q;
for(int i = 1; i <= n; ++i)
{
cin >> arr[i];
T.update(1, 100000, T.root[i], T.root[i - 1], arr[i]);
}
while(q--)
{
cin >> l >> r >> x >> y;
rsum = T.t[T.root[r]].sum - T.t[T.root[l - 1]].sum;
nowsum = ld(rsum) - ld(rsum) * ld(x) / ld(y);
ld fst = 0, lst = 100000, mid;
for(int i = 0; i < 100; ++i)
{
mid = (fst + lst) / 2.0;
if(check(mid))
fst = mid;
else
lst = mid;
}
cout <<fixed << setprecision(20) << mid << '
';
}
return 0;
}