李超线段树入门

李超线段树入门

算法总概

李超线段树用于维护线段和直线与某条直线交点的最值
类似一个凸包的东西

大致思路:

插入时通过线段树记录与更新,每个区间可能的最优的直线
查询时,对于覆盖在某个点之上的所有区间求其最值

插入的细节(现在考虑最大值):

  1. 若当前区间没有直线,加入当前直线即可
  2. "区间直线"整体在"插入直线"下,整体替换
  3. "插入直线"整体在"区间直线"下,不做更改
  4. 两直线有交点则判断交点的位置,并下放插入直线到左右儿子

code

例题(求所有直线与x=x0的交点的最大值)

#include<bits/stdc++.h>
using namespace std;
#define re register
#define ll long long
#define get getchar()
#define in inline
#define db double
const int _=2e5+234;
int n;
char ch[101];
struct LCXDtree{
	db b, k;
	int fl;
}a[_<<2];
#define ls k<<1
#define rs k<<1|1
in void insert(int k,int l,int r,db K,db B)
{
	if(l>r) return;
	if(!a[k].fl){ a[k].fl=1; a[k].k=K, a[k].b=B; return;}
	int l1=a[k].k*(l-1)+a[k].b, l2=K*(l-1)+B, r1=a[k].k*(r-1)+a[k].b, r2=K*(r-1)+B;
	if(l1>=l2 && r1>=r2) return;
	if(l1<l2 && r1<r2){ a[k].k=K, a[k].b=B; return;}
	int mid=l+r>>1, mid1=a[k].k*(mid-1)+a[k].b, mid2=K*(mid-1)+B;
	if(l1<l2)
	{
		insert(ls,l,mid,K,B);
		if(mid1<mid2) insert(rs,mid+1,r,K,B);
	}
	else
	{
		insert(rs,mid+1,r,K,B);
		if(mid1<mid2) insert(ls,l,mid,K,B);
	}
}
in db query(int k,int l,int r,int x)
{
	if(l==r) return a[k].k*(l-1)+a[k].b;
	int mid=l+r>>1; db w=a[k].k*(x-1)+a[k].b;
	if(x<=mid) return max(w,query(ls,l,mid,x));
	else return max(w,query(rs,mid+1,r,x));
}
int main()
{
	int T; cin>>T; n=50000;
	while(T--)
	{
		cin>>ch+1;
		if(ch[1]=='P')
		{
			db x,y; scanf("%lf%lf",&x,&y);
			insert(1,1,n,y,x);
		}
		else
		{
			int x; scanf("%d", &x);
			printf("%d\n", int(query(1,1,n,x))/100);
		}
	}
	return 0;
}
嗯,就这样了...
posted @ 2021-09-12 22:03  yzhx  阅读(26)  评论(0编辑  收藏  举报