CF431E Chemistry Experiment

题意:有n个试管,有高度为hi的水银。操作1:将试管x中的水银高度改成y。操作2:将体积为v的水注入试管,求水位的高度?n,q<=1e5。

标程:

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 typedef long long ll;
 4 const int N=1e5+5;
 5 int n,q,x,y,h[N],sc,rt,ls[N*40],rs[N*40],num[N*40];
 6 ll sum[N*40],v;
 7 void add(int &k,int l,int r,int x,int y)
 8 {
 9     if (!k) k=++sc;
10     if (l==r) {num[k]+=y;sum[k]+=x*y;return;}
11     int mid=(l+r)>>1;
12     if (x<=mid) add(ls[k],l,mid,x,y);
13     else add(rs[k],mid+1,r,x,y);
14     sum[k]=sum[ls[k]]+sum[rs[k]];
15     num[k]=num[ls[k]]+num[rs[k]];
16 }
17 double qry(int k,int l,int r,ll Num,ll Sum)
18 {
19     if (!k||l==r) return (double)(v+Sum+sum[k])/(Num+num[k]);
20     int mid=(l+r)>>1;
21     if ((ll)(mid+1)*(Num+num[ls[k]])-(Sum+sum[ls[k]])>=v) return qry(ls[k],l,mid,Num,Sum);
22     else return qry(rs[k],mid+1,r,Num+num[ls[k]],Sum+sum[ls[k]]);
23 }
24 int main()
25 {
26   scanf("%d%d",&n,&q);
27   for (int i=1;i<=n;i++) scanf("%d",&h[i]),add(rt,0,1e9,h[i],1);
28   while (q--)
29   {
30      int op;scanf("%d",&op);
31      if (op==1)
32      {
33          scanf("%d%d",&x,&y);
34          add(rt,0,1e9,h[x],-1);
35          add(rt,0,1e9,y,1);
36          h[x]=y;
37      }else {
38          scanf("%lld",&v);
39          printf("%.8lf\n",qry(rt,0,1e9,0,0));
40      }
41   }
42   return 0;
43 }

易错点:1.写得太急又忘记ll了啊。

2.注意把水银和水分清楚啊。

题解:线段树+二分

考虑二分高度hi,当hi*num(高度<hi的试管数量)-sum(这些试管中已有水银的高度之和)<v,那么说明高度太小,还可以再倒水。放在线段树上也是一样的哈。注意是要小数,但是给你的所有高度都是整数,那么就统计水盖过的最上一个试管高度,从而计算出实际的h。

权值线段树维护某高度区间的水银数量,以及这些水银高度的和。

猜你喜欢

转载自www.cnblogs.com/Scx117/p/9107931.html