二分用于在单调序列上以logn的时间确定某个值,三分则用在凸函数上,即先增后减序列,可以找它的极值。我们需要mid=(l+r)/2和midmid=(mid+r)/2这两个分界点,前者大则令r=midmid,否则令l=mid。

例题:cf939E

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
#include<bits/stdc++.h>
using namespace std;

const int maxn=5e5+1;

double a[maxn];
double sum[maxn];

int p,q;

#define cal(k) (a[p]-(a[p]+sum[k])/(k+1))


int main(){
    cin>>q;
    while(q--){
        int tp;
        cin>>tp;
        if(tp==1){
            double x;
            cin>>x;
            a[++p]=x;
            sum[p]=sum[p-1]+a[p];
        }else{
            int l=1,r=p;	//三分
            while(l<r-1){
                int mid=(l+r)/2;
                int midmid=(mid+r)/2;
                if(cal(mid)<cal(midmid)){
                    l=mid;
                }else{
                    r=midmid;
                }
            }
            double ans=max(cal(l),cal(r));
            printf("%.6f\n",ans);
        }
    }
    return 0;
}