1. 程式人生 > >Luogu 4254 [JSOI2008]Blue Mary開公司

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\n", (ll) (ans / 100.0)); } } return 0; }
View Code