【学习笔记】李超线段树

李超线段树

洛谷模板题

题目描述

要求在平面直角坐标系下维护两个操作:

  1. 在平面上加入一条线段。记第 i 条被插入的线段的标号为 i
  2. 给定一个数 k,询问与直线 x=k 相交的线段中,交点纵坐标最大的线段的编号。

线段端点横坐标范围40000,考虑用线段树维护,线段树的每一个点上维护一条线段。
线段树上一点的 tag 即为对应的线段。
当然因为线段左右端点有范围,所以要先找到线段树对应的区间。
而后讨论当前线段和当前点对应的线段关系。
具体看代码。

点击查看代码
#include<bits/stdc++.h>
using namespace std;
inline int rd(){
	int f=1,j=0;
	char w=getchar();
	while(w>'9'||w<'0'){
		if(w=='-')f=-1;
		w=getchar();
	}
	while(w>='0'&&w<='9'){
		j=(j<<3)+(j<<1)+w-'0';
		w=getchar();
	}
	return f*j;
} 
const int N=100001,M=40000,mod=39989,mod2=1000000000;
const double E=0.0000001;
struct Line{
	double k,b;
	inline double operator [](int x){return k*x+b;}
}lin[N];
struct node{
	int l,r,t;
}tr[M*20];
int n,tail,lastans,siz,ans;
inline void addline(int t,int xa,int ya,int xb,int yb){
	if(xa==xb)lin[t].k=0,lin[t].b=max(ya,yb);
	else lin[t].k=(double)(yb-ya)/(xb-xa),lin[t].b=(double)ya-lin[t].k*xa;
	return ;
}
void add(int u,int l,int r,int L,int R,int t){
	int mid=(l+r)/2;
	if(L<=l&&r<=R){
		if(!tr[u].t||(lin[tr[u].t][l]<lin[t][l]&&lin[tr[u].t][r]<lin[t][r])){
			tr[u].t=t;
			return ;
		}
		if(l==r||(lin[tr[u].t][l]>lin[t][l]&&lin[tr[u].t][r]>lin[t][r]))return ;
		if(lin[tr[u].t][mid]<lin[t][mid])swap(tr[u].t,t);
		if(lin[tr[u].t][l]<=lin[t][l])add(u*2,l,mid,L,R,t);
		else if(lin[tr[u].t][r]<=lin[t][r])add(u*2+1,mid+1,r,L,R,t);
		return ;
	}
	else{
		if(L<=mid)add(u*2,l,mid,L,R,t);
		if(mid<R)add(u*2+1,mid+1,r,L,R,t);
	}
	return ;
}
void getans(int u,int l,int r,int aim){
	if(tr[u].t&&(lin[tr[u].t][aim]>lin[ans][aim]||(tr[u].t<ans&&lin[tr[u].t][aim]>lin[ans][aim]-E&&lin[tr[u].t][aim]<lin[ans][aim]+E)))ans=tr[u].t;
	if(l==r)return ;
	int mid=(l+r)/2;
	if(aim<=mid)getans(u*2,l,mid,aim);
	else getans(u*2+1,mid+1,r,aim);
	return ;
}
signed main(){
	n=rd();
	lin[0].k=lin[0].b=-1;
	while(n--){
		int op=rd();
		if(op==1){
			int xa=(rd()+lastans-1)%mod+1,ya=(rd()+lastans-1)%mod2+1,xb=(rd()+lastans-1)%mod+1,yb=(rd()+lastans-1)%mod2+1;
			if(xa>xb)swap(xa,xb),swap(ya,yb);
			addline(++siz,xa,ya,xb,yb);
			add(1,1,mod,xa,xb,siz);
		}
		else{
			ans=0;
			getans(1,1,mod,(rd()+lastans-1)%mod+1);
			printf("%d\n",lastans=ans);
		}
	}
	return 0;
}

我才不会说因为交点精度问题被卡了好几次呢

标记永久化

看到luogu上好多题解都说什么标记永久化之类的,一直不明白是什么东西。
如果按照自己的理解来说,这大概是一种类似与树上子树整体修改(改子树根节点,求单点权值即求点到根的路径和)
类似的,标记永久化即标记打到包含其所有情况的点,状态不下传,求单点状态就从当前点跑到根。

posted @   flywatre  阅读(26)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
点击右上角即可分享
微信分享提示