[可持久化权值树] Cutting Bamboos

题意:

给定区间, 切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;
}
原文地址:https://www.cnblogs.com/zeolim/p/12270342.html