最近做多校联赛的时候,遇到了一道不会做的题,题解上写需要用到李超树,所以就去学习了一下。
参考博客: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
#include
#include
#include
#include
#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]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);
}
}
}