李超树 学习笔记

最近做多校联赛的时候,遇到了一道不会做的题,题解上写需要用到李超树,所以就去学习了一下。

参考博客:http://blog.csdn.net/clover_hxy/article/details/52503987

李超树的经典题目是bzoj的1568。
在一个平面里面,有两种操作:
1.每次在一个平面插入一个条直线(给出两个端点(x0,y0)和(x1,y1))
2.询问与x=k的相交的直线中,最上面的直线是哪一条。

对于这道题,以x轴开一棵线段树,每一个点记的是这个点所代表的区间里,与中点mid相交的线段中最高的是哪一条。
插入一条线段的时候,比较中点,即x取mid两个线段的值,如果斜率高的线段mid的大,那么[mid+1,r]这个线段一定是斜率高的直线更高,递归更新[l,mid]这个线段的,如果斜率高的线段mid的小,那么[l,mid]的值一定是斜率小的线段好,递归更新[mid+1,r]这个线段。注意要递归之前更新当前节点的值。
找答案的时候要从表示x=k的节点以及它祖先的所有线段都要找一下哪一条最高

#include<iostream>  
#include<cstdio>  
#include<algorithm>  
#include<cmath>  
#include<cstring>  
#define N 500003  
using namespace std;  
int n,m,tr[N*4];  
double a[N*2],b[N*2];  
int pd(int x,int y,int pos)  
{  
    return a[x]+(pos-1)*b[x]>a[y]+(pos-1)*b[y];  
}  
void change(int now,int l,int r,int x)  
{  
    if (l==r)    
    {  
        if (pd(x,tr[now],l))  
          tr[now]=x;  
        return;  
    }  
    int mid=(l+r)/2;  
    if (b[x]>b[tr[now]])  
     if (pd(x,tr[now],mid))  
      change(now<<1,l,mid,tr[now]),tr[now]=x;  
     else change(now<<1|1,mid+1,r,x);  
    if (b[x]<b[tr[now]])  
     if (pd(x,tr[now],mid))  
      change(now<<1|1,mid+1,r,tr[now]),tr[now]=x;  
     else change(now<<1,l,mid,x);  
}  
double getans(int k,int x)  
{  
    return a[k]+(x-1)*b[k];  
}  
double qjmax(int now,int l,int r,int x)  
{  
    if (l==r)  return getans(tr[now],x);  
    int mid=(l+r)/2;  
    double ans=getans(tr[now],x);  
    if (x<=mid)  ans=max(ans,qjmax(now<<1,l,mid,x));  
    else ans=max(ans,qjmax(now<<1|1,mid+1,r,x));  
    return ans;  
}  
int main()  
{  
    freopen("a.in","r",stdin);  
    freopen("my.out","w",stdout);  
    scanf("%d",&n);  
    for (int i=1;i<=n;i++)  
    {  
        char s[20]; scanf("%s",s);  
        if (s[0]=='P')  
         {  
            m++;  
            scanf("%lf%lf",&a[m],&b[m]);  
            change(1,1,N,m);  
         }  
        else  
        {  
            int x; scanf("%d",&x);  
            double t=qjmax(1,1,N,x);  
            int k=t;   
            printf("%d\n",k/100);  
        }  
    }  
}  
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值