首页 > 其他分享 >李超线段树

李超线段树

时间:2025-01-21 14:55:58浏览次数:1  
标签:int 线段 李超 dat ls x0 define

更新日志 2025/01/21:开工。

用处

\(O(n\log n)\) 解决这个问题

实现

首先,我们肯定需要一棵线段树,区间为横轴。

我们考虑每一段都储存最优的线段,但考虑到线段必然有交点,所以会有较为复杂的情况,下面详细考虑:

首先考虑单纯的储存线段,我们把线段横轴影射区间区间修改即可。

下面考虑同一区间多条线段的情况。

首先,如果一个线段完全优于另一个,那么就可以把劣的那个删掉了。

接下来考虑交点情况,如何解决呢?我们令中点上最优的线段为当前最优线段,并把另一条线段下放到可能的最优位置。如果交点在左侧,说明其在左侧有可能的最优区间,在左子节点加入这个劣线段;右侧同理。

下面考虑查询,我们直接把走到这个节点上经过的所有答案取最优值即可,这样就解决了上面把线段下方产生的问题。

模板

struct line{
    db k,b;
    db y(db x){return k*x+b;}
}ls[N];
struct lsegment{
    int dat[M*4+5];
    void insert(int lq,int rq,int id,int x=1,int l=1,int r=M){
        if(l==lq&&r==rq){
            if(!dat[x]){
                dat[x]=id;
                return;
            }
            int m=l+r>>1;
            if(ls[dat[x]].y(m)<ls[id].y(m))swap(dat[x],id);
            if(ls[id].y(l)>ls[dat[x]].y(l))insert(l,m,id,x<<1,l,m);
            if(ls[id].y(r)>ls[dat[x]].y(r))insert(m+1,r,id,x<<1|1,m+1,r);
            return;
        }
        int m=l+r>>1;
        if(rq<=m)insert(lq,rq,id,x<<1,l,m);
        else if(m<lq)insert(lq,rq,id,x<<1|1,m+1,r);
        else insert(lq,m,id,x<<1,l,m),insert(m+1,rq,id,x<<1|1,m+1,r);
    }
    int query(int k,int x=1,int l=1,int r=M){
        if(l==r)return dat[x];
        int m=l+r>>1,res;
        if(k<=m)res=query(k,x<<1,l,m);
        else res=query(k,x<<1|1,m+1,r);
        if(!res||ls[dat[x]].y(k)>ls[res].y(k))res=dat[x];
        return res;
    }
}lseg;

细节

对于这道例题,上面的代码是无法通过的。

你需要开 long double,特判相等情况,以及当心精度问题。

代码

#include<bits/stdc++.h>
using namespace std;

typedef long long ll;
typedef unsigned long long ull;
typedef __int128 i128;
typedef long double db;
typedef pair<int,int> pii;
typedef pair<ll,ll> pll;
typedef pair<int,ll> pil;
typedef pair<ll,int> pli;
template <typename Type>
using vec=vector<Type>;
template <typename Type>
using grheap=priority_queue<Type>;
template <typename Type>
using lrheap=priority_queue<Type,vector<Type>,greater<Type> >;
#define fir first
#define sec second
#define pub push_back
#define pob pop_back
#define puf push_front
#define pof pop_front
#define chmax(a,b) a=max(a,b)
#define chmin(a,b) a=min(a,b)
#define rep(i,x,y) for(int i=(x);i<=(y);i++)
#define repl(i,x,y) for(int i=(x);i<(y);i++)
#define per(i,x,y) for(int i=(x);i>=(y);i--)

const int inf=0x3f3f3f3f;
const ll INF=0x3f3f3f3f3f3f3f3f;
const int mod=998244353;

const int N=1e5+5,M=39989;

struct line{
    db k,b;
    db y(db x){return k*x+b;}
}ls[N];
struct lsegment{
    int dat[M*4+5];
    void insert(int lq,int rq,int id,int x=1,int l=1,int r=M){
        if(l==lq&&r==rq){
            if(!dat[x]){
                dat[x]=id;
                return;
            }
            int m=l+r>>1;
            if(ls[dat[x]].y(m)<ls[id].y(m)||fabs(ls[dat[x]].y(m)-ls[id].y(m))<1e-10&&id<dat[x])swap(dat[x],id);
            if(ls[id].y(l)>ls[dat[x]].y(l)||fabs(ls[dat[x]].y(l)-ls[id].y(l))<1e-10&&id<dat[x])insert(l,m,id,x<<1,l,m);
            if(ls[id].y(r)>ls[dat[x]].y(r)||fabs(ls[dat[x]].y(r)-ls[id].y(r))<1e-10&&id<dat[x])insert(m+1,r,id,x<<1|1,m+1,r);
            return;
        }
        int m=l+r>>1;
        if(rq<=m)insert(lq,rq,id,x<<1,l,m);
        else if(m<lq)insert(lq,rq,id,x<<1|1,m+1,r);
        else insert(lq,m,id,x<<1,l,m),insert(m+1,rq,id,x<<1|1,m+1,r);
    }
    int query(int k,int x=1,int l=1,int r=M){
        if(l==r)return dat[x];
        int m=l+r>>1,res;
        if(k<=m)res=query(k,x<<1,l,m);
        else res=query(k,x<<1|1,m+1,r);
        if(!res||ls[dat[x]].y(k)>ls[res].y(k))res=dat[x];
        else if(res&&dat[x]&&fabs(ls[dat[x]].y(k)-ls[res].y(k))<1e-10&&dat[x]<res)res=dat[x];
        return res;
    }
}lseg;

int n,m,ans;

int main(){
	ios::sync_with_stdio(false);
	cin.tie(0);cout.tie(0);
	cin>>n;
    int op,x0,y0,x1,y1;
    rep(i,1,n){
        cin>>op;
        if(op){
            ++m;
            cin>>x0>>y0>>x1>>y1;
            x0=(x0+ans-1)%39989+1,x1=(x1+ans-1)%39989+1;
            y0=(y0+ans-1)%(int)1e9+1,y1=(y1+ans-1)%(int)1e9+1;
            if(x0>x1)swap(x0,x1),swap(y0,y1);
            if(x0!=x1)ls[m].k=db(y1-y0)/(x1-x0),ls[m].b=y0-ls[m].k*x0;
            else ls[m].k=0,ls[m].b=max(y0,y1);
            lseg.insert(x0,x1,m);
        }else{
            cin>>x0;
            x0=(x0+ans-1)%39989+1;
            ans=lseg.query(x0);
            cout<<ans<<"\n";
        }
    }
    return 0;
}

应用

可以用来斜率优化

标签:int,线段,李超,dat,ls,x0,define
From: https://www.cnblogs.com/HarlemBlog/p/18683582

相关文章

  • 线段树
    [线段树]本质为二叉树用来区间查询,区间修改,单点查询,单点修改运用结构体存储。structnode{ intsum,laze;}tree[N*4];//四倍空间//建树voidbuild_tree(intid,intl,intr){ if(l==r){ tree[id].sum=a[l]; return; } intmid=(l+r)/2; build_tree(id*2,l,mid)......
  • 2025 刷题计划 - 线段树
    2025刷题计划-线段树A.P3313[SDOI2014]旅行树剖板子题,开\(C\)棵线段树即可。你可能会说开不下?动态开点不就完了。B.P3924康娜的线段树有意思的一道题,貌似\(O(n\logn)\)解法比\(O(n)\)更难?我实现不出来。首先易得期望的计算方式即为:设当前节点\(x\)的深度为......
  • 使用矩阵乘法维护的线段树
    车人去WC了,找了一个巴蜀毕业的哈工大大三学生来给他代课。那就简单记录一下每天都讲了什么吧CFGYM103470PaimonSegmentTree给定一个长度为\(n\)的序列\(a\),以及\(m\)次区间加操作和\(q\)次询问(在处理完所有操作后再询问)。询问操作:假设\(a_{i,j}\)表示进行完第......
  • 线段树
    海亮OJ题单维护差分信息P4243[JSOI2009]等差数列若要在序列上处理等差数列,可以考虑差分法。此时,我们不必将差分数组和数列中的元素一一对应(这会影响理解),而是将差分数组中的一个元素和原序列中对应的两个元素关联(我的理解盲区)。这样,使用线段树时,对于(差分数组的下标)区间\([......
  • 【做题记录】2025刷题计划--线段树
    A.「SDOI2014」旅行给每个宗教开一棵线段树,树剖\(+\)线段树单点修改区间查询即可。Code#include<bits/stdc++.h>#definelllonglong#defineilinline#defineread(x){\ charch;\ intfu=1;\ while(!isdigit(ch=getchar()))\ fu-=(ch=='-')<<1;\ x=ch&1......
  • 计算几何~三角形面积、点在三角形内、线段相交代码笔记
    多边形面积的基本公式:鞋带公式。强调多边形点集是按顺序存储;三角形面积基本公式:海伦公式;向量叉积公式;拓扑关系判断:判断点是否在三角形内;判断两条线段是否相交;代码笔记:#pragmaonce#include<iostream>#include<vector>#include<algorithm>#include<cmath>#in......
  • 势能线段树
    简介通过定义势能函数\(\phi(i)\)去描绘整个序列的势能从而推导正确的复杂度。例题P4145上帝造题的七分钟2/花神游历各国典。设\(\phi(i)\)表示第\(i\)个元素的势能。一个元素不停的开根一定会变成\(1\),不妨将元素\(x\)改写成\(2^k\)的形式。一次开根会将\(......
  • 线段树合并
    简介将多棵线段树的信息统一起来的高效算法称之为线段树合并。通常合并顺序呈树状结构。例题P3224[HNOI2012]永无乡假设所有点都在一个连通块里,那么我们只需要维护一个值域线段树并在上面二分即可。但此时图不连通,我们该如何快速的统计信息呢?对于连边,并查集可以胜任。对......
  • 洛谷题单指南-线段树的进阶用法-P3168 [CQOI2015] 任务查询系统
    原题链接:https://www.luogu.com.cn/problem/P3168题意解读:一个任务管理系统,能够查询在某个时间点运行的任务中优先级最小的k个任务的优先级之和。解题思路:由于总时间n不超过100000,考虑针对所有时刻建立可持久化线段树,根节点为root[i]的线段树维护时刻i的任务情况,节点区间表示......
  • 洛谷题单指南-线段树的进阶用法-P2617 Dynamic Rankings
    原题链接:https://www.luogu.com.cn/problem/P2617题意解读:动态求区间第k小问题。解题思路:树套树的典型应用,具体阐述参考:https://www.cnblogs.com/jcwy/p/18640914100分代码:#include<bits/stdc++.h>usingnamespacestd;constintN=100005;structOp{charop;......