李超线段树
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;
以上是关于李超线段树的主要内容,如果未能解决你的问题,请参考以下文章