李超线段树

时间:2021-09-06
本文章向大家介绍李超线段树,主要包括李超线段树使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

李超线段树

用途:给定 $\mathrm{n}$ 个 $\mathrm{y}=\mathrm{kx}+\mathrm{b}$ 形式的线段,问 $\mathrm{x}=\mathrm{x[0]}$ 与哪条线段交点的纵坐标值最大.

对于李超树的每一个区间,维护这条区间的 “优势线段”,即区间 $\mathrm{mid}$ 位置上纵坐标最大的线段.  

当在区间中插入一条线段时,按照下列步骤:

1. 若新插入线段中点位置大于当前线段,则该区间的优势线段更新为新线段,并将当前线段向下递归更新.

2. 若将递归更新的线段左/右端点的值小于优势线段,显然会完全被覆盖掉,就没有必要继续递归了.  

3. 若满足递归条件,则递归继续更新.  

插入线段时间复杂度为 $O(n \log ^2 n)$,查询复杂度为 $O(n \log n)$.   

Segment

来源:洛谷P4097 [HEOI2013]Segment

模板题,注意线段的 $\mathrm{x[0]}=\mathrm{x[1]}$ 时将斜率取为 $0$ 即可.   

#include <cstdio>
#include <cstring> 
#include <cmath>
#include <vector> 
#include <set>
#include <algorithm>
#define M  50003
#define N  100009 
#define ll long long 
#define pb push_back 
#define ls (now<<1) 
#define rs (now<<1|1)    
#define setIO(s) freopen(s".in","r",stdin)    
using namespace std; 
const int mod=39989; 
const double eps=1e-8;
int tree[N<<2];   
struct seg {
    double k,b;   
    seg(double i=0.0,double j=0.0) { k=i,b=j;}    
}s[N];  
double calc(seg o, int x) {
    return o.k*x+o.b;  
}    
void modify(int l,int r,int now,int L,int R,int x) {
    int mid=(l+r)>>1;  
    if(l>=L&&r<=R) {
        if(calc(s[x],mid)-calc(s[tree[now]],mid)>eps) swap(x, tree[now]);    
        if(calc(s[x],l)-calc(s[tree[now]],l)>eps) 
            modify(l,mid,ls,L,R,x); 
        if(calc(s[x],r)-calc(s[tree[now]],r)>eps) 
            modify(mid+1,r,rs,L,R,x);  
        return ; 
    }
    if(L<=mid) modify(l,mid,ls,L,R,x); 
    if(R>mid)  modify(mid+1,r,rs,L,R,x);  
}    
void upd(int &x,int o,int p) {
    double yx=s[x].k*p+s[x].b;  
    double yo=s[o].k*p+s[o].b;   
    if(yo-yx>=eps||(abs(yo-yx)<=eps&&o<x)) x=o;    
}
int query(int l,int r,int now,int p) {
    if(l==r) {
        return tree[now]; 
    }
    int mid=(l+r)>>1,id=tree[now];     
    if(p<=mid)  upd(id, query(l,mid,ls,p), p);  
    else upd(id, query(mid+1,r,rs,p), p);  
    return id;         
}
int main() { 
    // setIO("input");      
    // freopen("input.out","w",stdout);   
    int Q,lastans=0,n=0;  
    scanf("%d",&Q); 
    while(Q--) {
        int op; 
        scanf("%d",&op);  
        if(op==0) {
            int k,x; 
            scanf("%d",&k);  
            k=(k+lastans-1)%mod+1;  
            printf("%d\n",lastans=query(1,M,1,k));    
        }
        else {
            int x[2],y[2];  
            scanf("%d%d%d%d",&x[0],&y[0],&x[1],&y[1]);  
            x[0]=(x[0]+lastans-1)%mod+1;  
            y[0]=(y[0]+lastans-1)%1000000000+1;    
            x[1]=(x[1]+lastans-1)%mod+1; 
            y[1]=(y[1]+lastans-1)%1000000000+1;                            
            if(x[0]==x[1]) {
                s[++n].k=0,s[n].b=max(y[0], y[1]);    
            }
            else {
                s[++n].k=(double)1.0*(y[1]-y[0])/(x[1]-x[0]);  
                s[n].b=y[0]-1.0*s[n].k*x[0];     
            }
            if(x[0]>x[1]) swap(x[0],x[1]); 
            modify(1,M,1,x[0],x[1],n);  
        }
    }
    return 0; 
}

  

原文地址:https://www.cnblogs.com/brady12/p/15234637.html