李超线段树
动态维护一个平面直角坐标系,支持在中间插入一条线段,支持询问与 (x=x_0) 这条直线相交的所有线段中,交点的 (y) 轴坐标的最大(小)值。
想到把一条线段拆成 (x) 值为整数的点,这里 (y) 值开 (double) 就没有问题了
主要是考虑怎么插入一条直线,假设它当前处理到了某个区间:
-
区间没有记录最长的线段:那么直接把这个区间记录的线段修改为这条线段
-
当前线段在这个区间内已经被这个区间内的最长线段为覆盖: 直接返回。
-
完全覆盖了之前记录的线段: 区间修改
-
和已经记录的直线有交:判断哪根线段覆盖的区域较长,把这个区间记录的值给修改一下,然后把短的那一半丢下去递归。
查询还是很水的
Code Part
inline void insert(int p,int l,int r,int x1,int x2,node now)
{
if(l>=x1&&r<=x2)
{
int mid=(l+r)>>1;
if(calc(t[p],mid)<calc(now,mid)||(!t[p].num)) swap(t[p],now);
double jd=1.0*(t[p].b-now.b)/(now.k-t[p].k);
if(l==r||t[p].k==now.k||jd<1.0*l||jd>1.0*r||(!now.num)) return ;
if(now.k<t[p].k) insert(p<<1,l,mid,x1,x2,now);
else insert(p<<1|1,mid+1,r,x1,x2,now);
}
else
{
int mid=(l+r)>>1;
if(x1<=mid) insert(p<<1,l,mid,x1,x2,now);
if(x2>mid) insert(p<<1|1,mid+1,r,x1,x2,now);
}return ;
}
inline node query(int p,int l,int r,int x)
{
if(l==r) return t[p];
int mid=(l+r)>>1; node k;
if(x<=mid) k=query(p<<1,l,mid,x);
else k=query(p<<1|1,mid+1,r,x);
return ((!k.num)||calc(k,x)<calc(t[p],x))?t[p]:k;
}
例题
HEOI2013 Segment
确实是模板题,甚至上面的码就是粘的那里的