【学习笔记】李超线段树

李超线段树

动态维护一个平面直角坐标系,支持在中间插入一条线段,支持询问与 \(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

确实是模板题,甚至上面的码就是粘的那里的

posted @ 2020-02-15 19:44  yspm  阅读(194)  评论(0编辑  收藏  举报