李超线段树学习笔记

李超线段树

用途

主要用在维护一次函数的问题上,一般维护两个操作;
1.在平面上加入一条线段.记第 𝑖i 条被插入的线段的标号为 𝑖i,该线段的两个端点分别为 (𝑥0,𝑦0)(x_0,y_0),(𝑥1,𝑦1)(x_1,y_1).
2.给定一个数 𝑘k,询问与直线 𝑥 = k 相交的线段中,交点纵坐标最大的线段的编号(若有多条线段与查询直线的交点纵坐标都是最大的,则输出编号最小的线段).特别地,若不存在线段与给定直线相交,输出 0.(摘自oiwiki)
一般李超线段树只维护max , min 值

具体实现

插入操作

在插入一条线段时,一般分为2种情况
一.完全覆盖类型
无标题
如图 ,当插入一条线段时与原来的线段没有交叉 , 即为当前情况
此时只需将tree[nw].id修改即可;
二.有交叉类型
无标题

此时我们发现 nw 和 past 各有高有低 , 此时就需要比较mid;
如val[nw] > val[id] (x = mid)需要交换两者 , 否则不需要;
为什么呢?????(其实我当时也不是很懂 【但%出真理】)
首先看本图(此时val[nw] < val[past])
更新左右区间 , 左边因为val[past] > val[nw] 不必理会;
右边就需要更新 update(rs , mid + 1 , r , L , R , nw);
无标题
再看此图 , 就要交换;
这时发现val[nw'] > val[past'] (nw' = past , past' = nw)(x == l)
这时恰好更新左边;

例题

我的代码(QWQ)
#include <bits/stdc++.h>
using namespace std;
#define lson tree[rt].ls
#define rson tree[rt].rs
const int mod1 = 39989;
const int mod2 = 1e9;
double eps = 1e-9;
const int N = 1e6 + 10;
int n , lastans , tot , ans;
int root , cnt;
struct stu{
	int ls , rs , id;
};
stu tree[N];
struct st{
	double k , b;
};
st a[N];
bool cmp(int nw , int id , int x){
	if(a[nw].k * x + a[nw].b - a[id].k * x - a[id].b > eps) return 1;
	if(a[id].k * x + a[id].b - a[nw].k * x - a[nw].b > eps) return 0;
	return nw < id;
}
void update(int & rt , int l , int r , int L , int R , int nw){
	if(L > r || R < l) return;
	if(! rt) rt = ++ cnt;
	int mid = (l + r) >> 1;
	if(L <= l && r <= R){
		if(cmp(nw , tree[rt].id , l) && cmp(nw , tree[rt].id , r)){
			tree[rt].id = nw;
			return;
		}
		if(cmp(tree[rt].id , nw , l) && cmp(tree[rt].id , nw , r)) return;
		if(cmp(nw , tree[rt].id , mid)) swap(nw , tree[rt].id);
		if(cmp(nw , tree[rt].id , l)) update(lson , l , mid , L , R , nw);
		if(cmp(nw , tree[rt].id , r)) update(rson , mid + 1 , r , L , R , nw);
	}
	else update(lson , l , mid , L , R , nw) , update(rson , mid + 1 , r , L , R , nw);
}
void query(int rt , int l , int r , int nw){
	if(! rt || nw < l || nw > r) return;
	if(cmp(tree[rt].id , ans , nw)) ans = tree[rt].id;
	if(l == r) return;
	int mid = (l + r) >> 1;
	query(lson , l , mid , nw) , query(rson , mid + 1 , r , nw);
}
int main(){
	cin >> n;
	int op , k , x , y , x2 , y2;
	while(n --){
		cin >> op;
		if(op == 0){
			cin >> k;
			ans = 0;
			k = (k + lastans - 1) % mod1 + 1;
			query(root , 1 , 1e9 , k);
			lastans = ans;
			cout << ans << endl;
		}
		else{
			cin >> x >> y >> x2 >> y2;
			x = (x + lastans - 1) % mod1 + 1 , x2 = (x2 + lastans - 1) % mod1 + 1;
			y = (y + lastans - 1) % mod2 + 1 , y2 = (y2 + lastans - 1) % mod2 + 1;
			if(x2 < x) swap(x , x2) , swap(y , y2);
			tot ++;
			if(x != x2) a[tot].k = 1.0 * (y2 - y) / (x2 - x) , a[tot].b = 1.0 * y - a[tot].k * x;
			else a[tot].k = 0 , a[tot].b = max(y , y2);
			update(root , 1 , 1e9 , x , x2 , tot);
		}
	}
	return 0;
}
posted @ 2026-08-16 21:14  wang_daylight  阅读(14)  评论(0)    收藏  举报