嘘~ 正在从服务器偷取页面 . . .

CF431E Chemistry Experiment 题解


CF431E Chemistry Experiment 题解

题目链接:CF431E Chemistry Experiment

题意

\(n\) 支试管,每支试管装有 \(h_i\ \mathrm{ml}\)水银

\(q\) 次操作,操作有两种:

  • 1 p x:倒掉试管 \(p\) 的水银修改为 \(x\ \mathrm{ml}\)

  • 2 v:将 \(v\ \mathrm{ml}\) 水任意分配至 \(n\) 支试管里,最小化有的试管中最大体积,输出这个最小值

    误差不超过 \(10^{-4}\) 算作正确(这个操作只是一次假想,不会真的把水倒进试管里)。

输入格式

The first line contains two integers \(n\) and \(q\) ( \(1\le n,q\le 10^{5}\) ) — the number of tubes ans the number of experiment steps. The next line contains \(n\) space-separated integers: \(h_{1},h_{2},\cdots,h_{n}\) ( \(0\le h_{i}\le 10^{9}\) ), where \(h_{i}\) is the volume of mercury in the \(і\) -th tube at the beginning of the experiment.

The next \(q\) lines contain the game actions in the following format:

  • A line of form \(1\ p_{i}\ x_{i}\) means an action of the first type ( \(1\le p_{i}\le n,~ 0\le x_{i}\le 10^{9}\) ).
  • A line of form \(2\ v_{i}\) means an action of the second type ( \(1\le v_{i}\le 10^{15}\) ).

It is guaranteed that there is at least one action of the second type. It is guaranteed that all numbers that describe the experiment are integers.

输出格式

For each action of the second type print the calculated value. The answer will be considered correct if its relative or absolute error doesn't exceed \(10^{-4}\) .

数据范围

\(1\le n,q\le 10^5,~0\le h_i,x\le 10^9,~1\le v\le 10^{15}\)

容易发现,倒水一定是先倒水银较少的瓶子,如图所示(来自参考文献[1])

考虑二分最终高度 \(h\) ,令 \(x\) 为满足 \(a_x < h\) 的最大瓶子的下标,则体积应为 \[ V_e=\left(h-a_1\right)+\left(h-a_2\right)+\cdots+\left(h-a_x\right)=x h-\sum_{i=1}^x a_i \]\(V > V_e\) ,则说明水还能倒,增大 \(h\) 。反之减少 \(h\)

然后这个 \(a\) 是带修改的,考虑使用权值线段树维护,这样查询直接线段树上二分即可。

时间复杂度 \(\mathcal{O}(n \log M)\)

代码:

#include <bits/stdc++.h>
using namespace std;
#define int long long
#define INF 0x3f3f3f3f3f3f3f3f
void up(int &x,int y) { x < y ? x = y : 0; }
void down(int &x,int y) { x > y ? x = y : 0; }
#define N ((int)(1e5 + 15))
#define M ((int)(1e9 + 7))
#define ls(at) ch[at][0]
#define rs(at) ch[at][1]

int n,tot = 1,h[N],ch[N << 5][2],sum[N << 5],val[N << 5];
void add(int at,int l,int r,int h,int k)
{
    if(l == r) { val[at] += k; sum[at] += l * k; return; }
    int mid = (l + r) >> 1;
    if(h <= mid)
    {
        if(!ls(at)) ls(at) = ++tot;
        add(ls(at), l, mid, h, k);
    }else
    {
        if(!rs(at)) rs(at) = ++tot;
        add(rs(at), mid + 1, r, h, k);
    }
    val[at] = val[ls(at)] + val[rs(at)];
    sum[at] = sum[ls(at)] + sum[rs(at)];
}
double query(int at,int l,int r,int V)
{
    int mid, Ve, oc = 0, oV = 0;
    for(; l < r && at; )
    {
        mid = (l + r) >> 1;
        Ve = mid * (val[ls(at)] + oc) - (sum[ls(at)] + oV);
        if(V > Ve)
        {
            oc += val[ls(at)]; oV += sum[ls(at)];
            at = rs(at); l = mid + 1;
        }else { at = ls(at), r = mid; }
    }
    return (double)(V + oV) / (double) oc;
}
signed main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);cout.tie(0);
    // freopen("check.in","r",stdin);
    // freopen("check.out","w",stdout);
    cout << fixed << setprecision(8);
    int Q; cin >> n >> Q;
    for(int i = 1; i <= n; i++) { cin >> h[i]; add(1, 0, M, h[i], 1); }
    for(int op,x,y; Q--; )
    {
        if(cin >> op, op == 1)
        {
            cin >> x >> y;
            add(1, 0, M, h[x], -1);
            add(1, 0, M, h[x] = y, 1);
        }else
        {
            cin >> x;
            cout << query(1, 0, M, x) << '\n';
        }
    }
    return 0;
}

参考文献

[1] https://yhx-12243.github.io/OI-transit/records/cf431E.html


文章作者: q779
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-ND 4.0 许可协议。转载请注明来源 q779 !
评论
  目录