今天我们讲讲李超树又称LCT(x),它主要支持2种操作:
- 在平面上插入一条直线
- 求一个横坐标上最高的直线
然后我们可以标记永久化,单点查询就非常简单了,而我们主要讲讲插入直线。对于线段树上一个点,你需要保留在这个区间的中点最高的直线,而插入时,新直线和旧直线进行比较:
-
当新直线在左右端点的值都比旧直线大,那么直接用新直线替代旧直线
-
当新直线在左右端点的值都比旧直线小,那么直接结束,不做任何操作
-
当新直线在区间中点的值比旧直线大,那么替换旧直线,但是要将旧直线插入左区间或右区间:
- 当新直线斜率更小,那么将旧直线插入到右区间中
- 当新直线斜率更大,那么将旧直线插入到左区间中
-
当新直线在区间中点的值比旧直线小,那么将新直线插入左区间或右区间:
- 当新直线斜率更小,将新直线插入到左区间中
- 当新直线斜率更大,将新直线插入到右区间中
显然,这样插入的复杂度是 O ( l o g n ) O(logn) O(logn)的。
其实就是刚刚的操作。
#include<bits/stdc++.h>
using namespace std;
#define N 50000
//#define eps 1e-10
inline int read(){
int a=0;char c=getchar();
while(c>'9'||c<'0')c=getchar();
while('0'<=c&&c<='9'){
a=a*10+c-48;
c=getchar();
}
return a;
}
#define MN 100005
struct line{
double k,b;
}w[MN];
int use[MN<<2],n;
double f(int id,int pos){
return w[id].k*pos+w[id].b;
}
#define Ls (x<<1)
#define Rs (x<<1|1)
#define mid (l+r>>1)
void Ins(int x,int l,int r,int id){
int v=use[x];
if(f(id,l)>f(v,l)&&f(id,r)>f(v,r)){
use[x]=id;
// cout<<"INS: "<<l<<" "<<r<<endl;
return;
}
if(f(id,l)<=f(v,l)&&f(id,r)<=f(v,r))return;
if(f(id,mid)>f(v,mid)){
if