李超线段树

李超线段树

李超线段树是一种维护空间一次函数的结构。
定义线段树中的一个节点l~r所表示的区间为一个空间“域”的话。
定义最优势直线为区间为整个区间自上而下覆盖范围最广的直线。
线段树中储存的信息,实际上是每个空间“域”内最优势的一次函数。
从本质上来讲李超树,是一种标记永久化的线段树。
它每次推标记的时候都会二分向左或者向右,不会同时向两边推标记,这就使得它可以暴力推标记推到叶子节点。
讲解

模版

智乃的直线

点击查看代码
#include<functional>
#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<complex>
#include<string>
#include<cstdio>
#include<vector>
#include<cmath>
#include<queue>
#include<deque>
#include<stack>
#include<map>
#include<set>
#define ll long long 
#define pa pair<int,int>
using namespace std;
const int maxn=8e6+10101;
const int MOD=998244353;
const int inf=2147483647;
const double pi=acos(-1);
const double eps=1e-12;
int read(){
    int x=0,f=1;char ch=getchar();
    for(;!isdigit(ch);ch=getchar())if(ch=='-')f=-1;
    for(;isdigit(ch);ch=getchar())x=x*10+ch-'0';
    return x*f;
}
struct line{
    double k,b;
    int l,r,flag;
    line(){k=b=0.0,flag=0;}
    double calc(double pos){
        return k*pos+b;
    }
    int cross(line x){
        return floor((b-x.b)/(x.k-k));
    }
}tr[maxn],tre[maxn];

int n,m;
void update(int k,int l,int r,line add){
    if(add.l<=l && r<=add.r){
        if(!tr[k].flag){
            tr[k]=add;
        }
        else if(add.calc(l)-tr[k].calc(l)>eps && add.calc(r)-tr[k].calc(r)>eps){
            tr[k]=add;
        }
        else if(add.calc(l)-tr[k].calc(l)>eps || add.calc(r)-tr[k].calc(r)>eps){
            int mid=(l+r)>>1;
            if(add.calc(mid)-tr[k].calc(mid)>eps)swap(tr[k],add);
            if(add.cross(tr[k])-mid<-eps)update(k<<1,l,mid,add);
            else update(k<<1|1,mid+1,r,add);
        }
    }
    else {
        int mid=(l+r)>>1;
        if(add.l<=mid)update(k<<1,l,mid,add);
        if(add.r>mid)update(k<<1|1,mid+1,r,add);
    }
    return ;
}
void update1(int k,int l,int r,line add){
    if(add.l<=l && r<=add.r){
        if(!tre[k].flag){
            tre[k]=add;
        }
        else if(tre[k].calc(l)-add.calc(l)>eps && tre[k].calc(r)-add.calc(r)>eps){
            tre[k]=add;
        }
        else if(tre[k].calc(l)-add.calc(l)>eps || tre[k].calc(r)-add.calc(r)>eps){
            int mid=(l+r)>>1;
            if(tre[k].calc(mid)-add.calc(mid)>eps)swap(tre[k],add);
            if(add.cross(tre[k])-mid<-eps)update1(k<<1,l,mid,add);
            else update1(k<<1|1,mid+1,r,add);
        }
    }
    else {
        int mid=(l+r)>>1;
        if(add.l<=mid)update1(k<<1,l,mid,add);
        if(add.r>mid)update1(k<<1|1,mid+1,r,add);
    }
    return ;
}
double querymax(int k,int l,int r,int x){
    if(l==r)return tr[k].calc(x);
    int mid=(l+r)>>1;
    double ans=tr[k].calc(x);
    if(x<=mid && tr[k<<1].flag)ans=max(ans,querymax(k<<1,l,mid,x));
    else if(tr[k<<1|1].flag)ans=max(ans,querymax(k<<1|1,mid+1,r,x));
    return ans;
}
double querymin(int k,int l,int r,int x){
    if(l==r){
        return tre[k].calc(x);
    }
    int mid=(l+r)>>1;
    double ans=tre[k].calc(x);
    if(x<=mid && tre[k<<1].flag)ans=min(ans,querymin(k<<1,l,mid,x));
    else if(tre[k<<1|1].flag)ans=min(ans,querymin(k<<1|1,mid+1,r,x));
    return ans;
}
int main(){
    n=read();m=read();
    for(int i=1;i<=m;i++){
        int opt=read();
        if(!opt){
            int k=read(),b=read();
            line now;
            now.k=k;now.b=b;now.l=1;now.r=n;now.flag=1;
            update(1,1,n,now);
            update1(1,1,n,now);
        }
        else {
            int x=read();
            printf("%lld %lld\n",(ll)querymax(1,1,n,x),(ll)querymin(1,1,n,x));
        }
    }
    return 0;
}

[HEOI2013]SEGMENT

点击查看代码
#include<functional>
#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<complex>
#include<string>
#include<cstdio>
#include<vector>
#include<cmath>
#include<queue>
#include<deque>
#include<stack>
#include<map>
#include<set>
#define ll long long 
#define pa pair<int,double>
using namespace std;
const int maxn=1e6+10101;
const int MOD=998244353;
const int inf=2147483647;
const double pi=acos(-1);
const double eps=1e-12;
int read(){
    int x=0,f=1;char ch=getchar();
    for(;!isdigit(ch);ch=getchar())if(ch=='-')f=-1;
    for(;isdigit(ch);ch=getchar())x=x*10+ch-'0';
    return x*f;
}
struct line{
    double k,b;
    int l,r,flag,id;
    line(){k=b=0.0,flag=id=0;}
    double calc(double pos){
        return k*pos+b;
    }
    int cross(line x){
        return floor((b-x.b)/(x.k-k));
    }
}tr[maxn];

int n,m;
void update(int k,int l,int r,line add){
    if(add.l<=l && r<=add.r){
        if(!tr[k].flag){
            tr[k]=add;
        }
        else if(add.calc(l)-tr[k].calc(l)>eps && add.calc(r)-tr[k].calc(r)>eps){
            tr[k]=add;
        }
        else if(add.calc(l)-tr[k].calc(l)>eps || add.calc(r)-tr[k].calc(r)>eps){
            int mid=(l+r)>>1;
            if(add.calc(mid)-tr[k].calc(mid)>eps)swap(tr[k],add);
            if(add.cross(tr[k])-mid<-eps)update(k<<1,l,mid,add);
            else update(k<<1|1,mid+1,r,add);
        }
    }
    else {
        int mid=(l+r)>>1;
        if(add.l<=mid)update(k<<1,l,mid,add);
        if(add.r>mid)update(k<<1|1,mid+1,r,add);
    }
    return ;
}
int last;
double jilu;
void querymax(int k,int l,int r,int x){
    if(l==r){
        if(tr[k].flag && tr[k].calc(x)-jilu>eps)jilu=tr[k].calc(x),last=tr[k].id;
        return ;
    }
    int mid=(l+r)>>1;
    if(tr[k].flag && tr[k].calc(x)-jilu>eps)jilu=tr[k].calc(x),last=tr[k].id;
    if(x<=mid)querymax(k<<1,l,mid,x);
    else querymax(k<<1|1,mid+1,r,x);
    return ;
}
int main(){
    n=read();int cnt=0;
    for(int i=1;i<=n;i++){
        int op=read();
        if(!op){
            int k=read();
            k=((k+last-1)%39989+1);jilu=0;last=0;
            querymax(1,1,40000,k);
            printf("%d\n",last);
        }
        else {
            int x0=read(),y0=read(),x1=read(),y1=read();
            x0=((x0+last-1)%39989+1);
            y0=((y0+last-1)%1000000000+1);
            x1=((x1+last-1)%39989+1);
            y1=((y1+last-1)%1000000000+1);
            if(x0>x1)swap(x0,x1),swap(y0,y1);
            line now;
            now.flag=1;
            if(x1==x0)now.k=0;
            else now.k=(double)(y1-y0)/(double)(x1-x0);
            now.b=(double)y0-(double)(now.k*(double)x0);
            now.l=x0;now.r=x1;now.id=++cnt;
            update(1,1,40000,now);
        }

    }
    return 0;
}
posted @   I_N_V  阅读(168)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!
点击右上角即可分享
微信分享提示