Luogu 4254 [JSOI2008]Blue Mary开公司

BZOJ 1568

学习了一波李超线段树。   

大佬blog

这个东西专门用来维护插入一条线段和区间/单点的最大/最小值。

插入的时候讨论:

1、如果当前结点上没有线段,那么直接插入。

2、如果当前结点上的线段一定比要插入的线段优/劣,那么直接覆盖或者返回。

3、如果当前结点上的线段和要插入的线段有交点,那么把优的部分比劣的部分多的线段放在当前结点上,然后把另一条线段下放给那个交点所在的儿子递归处理。

时间复杂度$O(nlogn)$,但是有返回这个操作看上去就很快……

Code:

#include <cstdio>
#include <cstring>
using namespace std;
typedef double db;
typedef long long ll;

const int N = 5e4 + 5;

int n = (int)5e4, qn;

template <typename T>
inline void chkMax(T &x, T y) {
    if(y > x) x = y;
}

namespace SegT {
    struct Node {
        db lb, lk;
        bool cov;
    } s[N << 2];
    
    #define lc p << 1
    #define rc p << 1 | 1
    #define mid ((l + r) >> 1)
    #define lb s[p].lb
    #define lk s[p].lk
    #define cov s[p].cov
    
    void ins(int p, int l, int r, db b, db k) {
        if(!cov) {
            lb = b, lk = k, cov = 1;
            return;
        }
        
        db l1 = 1.0 * l * k + b, r1 = 1.0 * r * k + b;
        db l2 = 1.0 * l * lk + lb, r2 = 1.0 * r * lk + lb;
        
        if(l1 >= l2 && r1 >= r2) {
            lb = b, lk = k;
            return;
        }
        if(l1 <= l2 && r1 <= r2) return;
        
        db x = (b - lb) / (lk - k);
        if(l1 > l2) {
            if(x > mid) ins(rc, mid + 1, r, lb, lk), lb = b, lk = k;
            else ins(lc, l, mid, b, k);
        } else {
/*            if(x <= mid) ins(lc, l, mid, lb, lk), lb = b, lk = k;
            else ins(rc, mid + 1, r, lb, lk);  */
            if(x > mid) ins(rc, mid + 1, r, b, k);
            else ins(lc, l, mid, lb, lk), lb = b, lk = k;
        }
    }
    
    db query(int p, int l, int r, int x) {
        if(l == r) return lk * x + lb;
        db res = lk * x + lb;
        if(x <= mid) chkMax(res, query(lc, l, mid, x));
        else chkMax(res, query(rc, mid + 1, r, x));
        return res;
    }
    
} using namespace SegT;

int main() {
    scanf("%d", &qn);
    for(char op[12]; qn--; ) {
        scanf("%s", op);
        if(op[0] == 'P') {
            db b, k;
            scanf("%lf%lf", &b, &k);
            b -= k;
            ins(1, 1, n, b, k);
        } else {
            int x; scanf("%d", &x);
            db ans = query(1, 1, n, x);
            printf("%lld
", (ll) (ans / 100.0));
        }
    }
    return 0;
} 
View Code
原文地址:https://www.cnblogs.com/CzxingcHen/p/10073011.html