题意:有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 ",qry(rt,0,1e9,0,0)); 40 } 41 } 42 return 0; 43 }
易错点:1.写得太急又忘记ll了啊。
2.注意把水银和水分清楚啊。
题解:线段树+二分
考虑二分高度hi,当hi*num(高度<hi的试管数量)-sum(这些试管中已有水银的高度之和)<v,那么说明高度太小,还可以再倒水。放在线段树上也是一样的哈。注意是要小数,但是给你的所有高度都是整数,那么就统计水盖过的最上一个试管高度,从而计算出实际的h。
权值线段树维护某高度区间的水银数量,以及这些水银高度的和。