李超线段树

李超线段树是一种用于维护平面内线段关系的数据结构。

[HEOI2013]Segment

\(\text{Solution}:\)

李超线段树模板。需要维护一种数据结构(即在线),支持在平面上插入一条线段,查询与直线 \(x=k\) 相交的线段中交点纵坐标最大的线段。

称一条线段在 \(x=x_{0}\) 处最优,当且仅当该线段在 \(x_{0}\) 处取值最大。

定义一条线段是区间 \([L,R]\) 的最优线段的条件为:

  • 这条线段的定义域完整覆盖了 \([L,R]\)
  • 这条线段在区间中点处最优

考虑对于一个区间 \([L,R]\),中点为 \(mid\),经尝试,我们发现只需要考虑新线段与原最优线段的斜率大小关系即可(与斜率正负无关)。

如果新线段斜率大于原最优线段的斜率:

  • 新线段在 \(mid\) 处更优,则新线段在右半区间最优,原最优线段在左半区间可能最优 \((1)\)
  • 原最优线段在 \(mid\) 处更优,则原最优线段在左半区间最优,新线段在右半区间可能最优。

另一种情况类似。特殊的,当斜率相同时,只需要比较截距即可。

在查询时,利用标记永久化的思想。具体的,对于 \((1)\),我们用原最优线段去更新左半区间,这样使得原最优线段不会被舍弃掉。那么我们最终得到 \(\log\) 个最优线段,比较它们在 \(x=k\) 处的 \(y\) 值即可。

易知插入和查询的时间复杂度均为 \(O(\log n)\)

\(\text{Code}:\)

#include <bits/stdc++.h>
#pragma GCC optimize(3)
#define int long long
#define ri register
#define mk make_pair
#define fi first
#define se second
#define pb push_back
#define eb emplace_back
#define is insert
#define es erase
using namespace std; const int N=200010, Mod=1e9;
inline int read()
{
	int s=0, w=1; ri char ch=getchar();
	while(ch<'0'||ch>'9') { if(ch=='-') w=-1; ch=getchar(); }
	while(ch>='0'&&ch<='9') s=(s<<3)+(s<<1)+(ch^48), ch=getchar();
	return s*w;
}
int n,m=39989,lsta;
struct Node
{
	double k,b;
}e[N]; int cnt;
int ans[N<<2];
#define lc (x<<1)
#define rc (x<<1|1)
void UpDate(int u,int v,int l,int r,int x,int g)
{
	int mid=(l+r)/2;
	if(l>=u&&r<=v)
	{
		if(!ans[x]) { ans[x]=g; return; }
		double py=e[ans[x]].b+e[ans[x]].k*mid;
		double ny=e[g].b+e[g].k*mid;
		if(l==r)
		{
			if(ny>py) ans[x]=g;
			return;
		}
		if(e[g].k==e[ans[x]].k)
		{
			if(e[g].b>e[ans[x]].b) ans[x]=g;
		}
		else if(e[g].k>e[ans[x]].k)
		{
			if(ny>py)
			{
				UpDate(u,v,l,mid,lc,ans[x]);
				ans[x]=g;
			}
			else UpDate(u,v,mid+1,r,rc,g);
		}
		else
		{
			if(ny>py)
			{
				UpDate(u,v,mid+1,r,rc,ans[x]);
				ans[x]=g;
			}
			else UpDate(u,v,l,mid,lc,g);
		}
		return;
	}
	if(u<=mid) UpDate(u,v,l,mid,lc,g);
	if(v>mid) UpDate(u,v,mid+1,r,rc,g);
}
inline int Ask(int pos,int l,int r,int x)
{
	int tt=0;
	if(ans[x]) tt=ans[x];
	if(l==r) return tt;
	int mid=(l+r)/2,g=0;
	if(pos<=mid) g=Ask(pos,l,mid,lc);
	else g=Ask(pos,mid+1,r,rc);
	if(!tt) return g;
	if(!g) return tt;
	double ty=e[tt].b+e[tt].k*pos;
	double gy=e[g].b+e[g].k*pos;
	if(gy>ty) return g;
	else if(gy<ty) return tt;
	else return min(g,tt);
}
#undef lc
#undef rc
signed main()
{
	n=read();
	for(ri int i=1;i<=n;i++)
	{
		int opt=read();
		if(opt)
		{
			int lx,ly,rx,ry;
			lx=(read()+lsta-1+m)%m+1, ly=(read()+lsta-1+Mod)%Mod+1;
			rx=(read()+lsta-1+m)%m+1, ry=(read()+lsta-1+Mod)%Mod+1;
			if(lx>rx) swap(lx,rx), swap(ly,ry);
			cnt++;
			if(lx==rx) e[cnt]=(Node){0.0,1.0*max(ly,ry)};
			else
			{
				e[cnt].k=1.0*(ry-ly)/(1.0*(rx-lx));
				e[cnt].b=1.0*ly-1.0*lx*e[cnt].k;
			}
			UpDate(lx,rx,1,m,1,cnt);
		}
		else
		{
			int k=(read()+lsta-1+m)%m+1;
			printf("%lld\n",lsta=Ask(k,1,m,1));
		}
	}
	return 0;
}
posted @ 2021-02-24 15:39  zkdxl  阅读(104)  评论(0编辑  收藏  举报