李超线段树

Posted pthws

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了李超线段树相关的知识,希望对你有一定的参考价值。

李超线段树:动态维护一个平面直角坐标系,支持在中间插入一条线段(或直线),询问与x=x0这条直线相交的所有线段中,交点的y坐标的最大(小)值。

线段树上每个区间维护在mid处y坐标最大的线段。(要标记永久化)

考虑怎么插入一条直线,假设它当前处理到了某个区间:(摘自yyb的博客https://www.cnblogs.com/cjyyb/p/10560973.html

  • 如果这个区间没有记录最长的线段,那么直接把这个区间记录的线段修改为这条线段,然后返回。
  • 如果当前线段在这个区间内已经被这个区间记录的线段覆盖,那么直接gg,返回就好了。
  • 反过来,如果完全覆盖了之前记录的线段,那么直接赋值、返回。
  • 否则和已经记录的直线有交,判断哪根线段覆盖的区域较长,把这个区间记录的值给修改一下,然后把短的那一半丢下去递归。
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    const int N=100005;
    int n,i;
    bool v[N*5];
    double x,y,K[N*5],B[N*5];
    char ch[20];
    void update(int o,int l,int r,double k,double b)
    
        if(!v[o])
        v[o]=true,K[o]=k,B[o]=b;return;
        if(l==r)
        
            if(k*l+b>K[o]*l+B[o])
                K[o]=k,B[o]=b;
            return;
        
        int mid=l+r>>1;
        double l1=k*l+b,r1=k*r+b,l2=K[o]*l+B[o],r2=K[o]*r+B[o];
        if(l1>=l2&&r1>=r2)
        K[o]=k,B[o]=b;return;
        if(l1<=l2&&r1<=r2)
            return;
        double x=(b-B[o])/(K[o]-k);
        if(l1>=l2)
        
            if(x>mid)
            update(o<<1|1,mid+1,r,K[o],B[o]);K[o]=k,B[o]=b;
            else
                update(o<<1,l,mid,k,b);
        
        else
        
            if(x>mid)
                update(o<<1|1,mid+1,r,k,b);
            else
            update(o<<1,l,mid,K[o],B[o]);K[o]=k,B[o]=b;
        
    
    double query(int o,int l,int r,int x)
    
        if(l==r)
            return K[o]*l+B[o];
        int mid=l+r>>1;
        double rtn=(v[o]?K[o]*x+B[o]:0.0);
        if(x<=mid)
            return max(rtn,query(o<<1,l,mid,x));
        else
            return max(rtn,query(o<<1|1,mid+1,r,x));
    
    int main()
    
        freopen("company.in","r",stdin);
        freopen("company.out","w",stdout);
        scanf("%d",&n);
        while(n--)
        
            scanf("%s",ch);
            if(ch[0]==P)
            
                scanf("%lf%lf",&x,&y);
                update(1,1,50000,y,x-y);
            
            else
            
                scanf("%d",&i);
                printf("%d\\n",max(0,(int)query(1,1,50000,i)/100));
            
        
        return 0;
    

     

以上是关于李超线段树的主要内容,如果未能解决你的问题,请参考以下文章

李超线段树 - JSOI2008BlueMary开公司

李超线段树

李超树详解

[CodeChef - STREETTA] The Street 李超线段树

CF932F(李超线段树+dp)

bzoj3165 segment 超哥线段树