P4254 [JSOI2008]Blue Mary开公司 (李超树)

题意:插入一些一次函数线段 每次询问在x = x0处这些线段的最大值

题解:李超树模版题 维护优势线段

   注意这题的输入是x=1时的b

 

#include <iostream>
#include <stdio.h>
using namespace std;
const int MAXT = 50000;
#define pff pair<double, double>

int tot, rt;
char s[50];
pff t[MAXT << 5];
int ls[MAXT << 5], rs[MAXT << 5];
double ans;

double fun(pff x, int y) {
    return x.first * (1.0 * (y - 1)) + x.second;
}

void add(int &k, int l, int r, pff x) {
    if(!k) {
        k = ++tot;
        t[k] = x;
        return;
    }

    int mid = l + r >> 1;
    if(fun(t[k], l) < fun(x, l) && fun(t[k], r) < fun(x, r)) {
        t[k] = x;
        return;
    }
    if(fun(t[k], l) > fun(x, l) && fun(t[k], r) > fun(x, r)) return;

    if(t[k].first < x.first) {
        if(fun(t[k], mid) < fun(x, mid)) add(ls[k], l, mid, t[k]), t[k] = x;
        else add(rs[k], mid + 1, r, x);
    } else {
        if(fun(t[k], mid) > fun(x, mid)) add(ls[k], l, mid, x);
        else add(rs[k], mid + 1, r, t[k]), t[k] = x;
    }
    /*
    if(fun(x, mid) > fun(t[k], mid)) swap(t[k], x);
    if(fun(x, l) > fun(t[k], l)) add(ls[k], l, mid, x);
    if(fun(x, r) > fun(t[k], r)) add(rs[k], mid + 1, r, x);
    */
}

double ask(int k, int l, int r, int x) {
    //if(!k) return -(1.0 * (1 << 30));
    if(l == r) return fun(t[k], x);
    int mid = l + r >> 1;
    double res = fun(t[k], x);
    if(x <= mid) return max(res, ask(ls[k], l, mid, x));
    else return max(res, ask(rs[k], mid + 1, r, x));
}

int main() {
    int T;
    cin>>T;
    while(T--) {
        scanf("%s", s + 1);
        if(s[1] == 'P') {
            double x, y;
            scanf("%lf%lf", &x, &y);
            add(rt, 1, MAXT, pff(y, x));
        } else {
            int x;
            scanf("%d", &x);
            printf("%d\n", (int)(ask(rt, 1, MAXT, x) / 100.0));
        }
    }
    return 0;
}
View Code

 

posted @ 2020-02-24 17:40  lwqq3  阅读(151)  评论(0编辑  收藏  举报