首页 > 其他分享 >李超线段树

李超线段树

时间:2024-10-06 15:01:13浏览次数:6  
标签:mod1 cnt int 线段 李超 yy xx

最经典应用就是维护一个二维平面直角坐标系,支持动态插入线段(理解为有值域的一次函数 \(y=kx+b\) ),询问已插入线段与直线 \(x=x_0\) 交点的纵坐标最值。

即当 \(x=x_0\) ,求 \(max\) 或 \(min\) { \(k_ix+b_i\) }

对于普通求法的 \(O(n)\) 遍历,如何优化时间复杂度呢?其实就是找一种方法减少有效集合大小,而李超线段树就是如此。

单次查询是 \(O(logn)\) 的,修改是 \(O(log^2n)\) 的。

现在我们需要插入一条线段 f,在这条线段完整覆盖的线段树节点代表的区间中,某些区间的最优线段可能发生改变。

考虑某个被新线段 f 完整覆盖的区间,若该区间无最优线段,则该线段可以直接成为最优线段。

否则,设该区间的中点为 mid,我们拿新线段 f 在中点处的值与原最优线段 g 在中点处的值作比较。

如果新线段 f 更优,则将 f 和 g 交换。

那么现在考虑在中点处 f 不如 g 优的情况:

若在左端点处 f 更优,那么f 和 g 必然在左半区间中产生了交点,递归到左儿子中进行插入;
若在右端点处 f 更优,那么 f 和 g 必然在右半区间中产生了交点,递归到右儿子中进行插入。
若在左右端点处 g 都更优,那么 f 不可能成为答案,不需要继续下传。

这个方法的优势就在于不需要讨论斜率的正负,十分方便。

//李超线段树 模版  [HEOI2013] Segment
#include<bits/stdc++.h>
#define lid (id<<1)
#define rid (id<<1|1)
#define pdi pair<double,int>
using namespace std;
const double eps=1e-9;//精度问题
const int maxn=1e5+5,mod1=39989,mod2=1000000000;
int n,cnt,ans,t[maxn<<1];
struct node{
	double k,b;
}p[maxn];
int cmp(double x,double y){
	if(x-y>eps) return 1;
	if(y-x>eps) return -1;
	return 0;
} 
double f(int id,int x){
	return p[id].b+p[id].k*x;
}
void add(int x,int y,int xx,int yy){
	cnt++;
	if(x==xx) p[cnt].k=0,p[cnt].b=max(y,yy);//特判直线斜率不存在的情况!
	else p[cnt].k=1.0*(yy-y)/(xx-x),p[cnt].b=y-p[cnt].k*x; 
}
void upd(int id,int l,int r,int u){//对线段完全覆盖到的区间进行修改 
	int &v=t[id],mid=(l+r)>>1;
	int tmp=cmp(f(u,mid),f(v,mid));
	if(tmp==1||(!tmp&&u<v)) swap(u,v);//交换新旧线段,这里是取地址的 
	int tl=cmp(f(u,l),f(v,l)),tr=cmp(f(u,r),f(v,r));
	if(tl==1||(!tl&&u<v)) upd(lid,l,mid,u);
	if(tr==1||(!tr&&u<v)) upd(rid,mid+1,r,u);
}
void change(int id,int l,int r,int vl,int vr,int u){
	if(vl<=l&&r<=vr){
		upd(id,l,r,u);
		return ;
	}
	int mid=(l+r)>>1;//线段树的查询 
	if(vl<=mid) change(lid,l,mid,vl,vr,u);
	if(mid<vr) change(rid,mid+1,r,vl,vr,u);
}
pdi pmax(pdi x,pdi y){
	if(cmp(x.first,y.first)==-1) return y;
	else if(cmp(x.first,y.first)==1) return x;
	else return x.second<y.second?x:y;
}
pdi query(int id,int l,int r,int pos){
	if(r<pos||pos<l) return {0,0};//一种比较方便的写法 
	double res=f(t[id],pos);
	if(l==r) return {res,t[id]};
	int mid=(l+r)>>1;
	return pmax({res,t[id]},pmax(query(lid,l,mid,pos),query(rid,mid+1,r,pos)));
}
int main(){
	scanf("%d",&n);
	while(n--){
		int op;
		scanf("%d",&op);
		if(op==1){
			int x,y,xx,yy;
			scanf("%d%d%d%d",&x,&y,&xx,&yy);
			x=(x+ans-1+mod1)%mod1+1;
			xx=(xx+ans-1+mod1)%mod1+1;
			y=(y+ans-1+mod2)%mod2+1;
			yy=(yy+ans-1+mod2)%mod2+1;
			if(x>xx) swap(x,xx),swap(y,yy);
			add(x,y,xx,yy);
			change(1,1,mod1,x,xx,cnt);
		}
		else{
			int x;
			scanf("%d",&x);
			x=(x+ans-1+mod1)%mod1+1;
			ans=query(1,1,mod1,x).second;
			printf("%d\n",ans);
		}
	}
	return 0;
} 

标签:mod1,cnt,int,线段,李超,yy,xx
From: https://www.cnblogs.com/YYYmoon/p/18449081

相关文章

  • B. 线段取交
    题目下载链接算法可以发现是求逆序对时间复杂度限制在\(O(n\logn)\)树状数组记录每一个值的多少转化为求前缀和#include<iostream>#include<cstdio>#include<algorithm>usingnamespacestd;inttree[500010],ranks[500010],n;longlongans;structpoint{......
  • 2024.10.1 总结(集训;数据结构 主要是线段树)
    XK又来给我们讲课了。开心!1.Baka'sTrick两种理解:双栈模拟队列。[找到若干个划分点,使得每个区间包含恰好一个划分点。维护划分点到划分点段的前缀、后缀信息。在在线的实现中,在队列中维护仅仅一个划分点,维护它到前面每个点和它到后面每个点的信息。当这个划分点出队时,把队......
  • 力扣(leetcode)每日一题 1845 座位预约管理系统| treeSet和priority Queue的区别|线段树
    之前发过一篇,感觉还有深挖的地方,于是又补充一些信息这题目虽然是middle难度题目,要解答出来是只要easy的时间,但是深挖可以有hard的难度题解1可以帮助复习线段树的使用,题解2可以复习一下java基础知识题解1线段树这是自己憋出来的线段树classSeatManager{......
  • Interval GCD(单点修改线段树)
    细节不少//根据更相减损法gcd(x,y)=gcd(x,y-x)//推广到三项为gcd(x,y,z)=gcd(x,y-x,z-y)//可以推广到n项#include<bits/stdc++.h>usingnamespacestd;#definexfirst#defineysecondtypedefpair<int,int>PII;typedeflonglongll;typedefunsignedlonglong......
  • Can you answer these queries III(单点修改线段树)
    因为洛谷出现UE在acwing提交,输入格式略有修改#include<bits/stdc++.h>usingnamespacestd;#definexfirst#defineysecondtypedefpair<int,int>PII;typedeflonglongll;typedefunsignedlonglongull;typedefvector<string>VS;typedefvector<int>......
  • P3372 【模板】线段树 1
    注意size信息应该存放在info里和tag运算,已经tag是表示子树未处理的信息#include<bits/stdc++.h>usingnamespacestd;#definexfirst#defineysecondtypedefpair<int,int>PII;typedeflonglongll;typedefunsignedlonglongull;typedefunsignedintuint;typede......
  • WPF 基础 2D 图形学知识 判断点是否在线段上
    在知道一个使用两个点表示的线段,和另一个点,求另一个点是否在线段上本文算法属于通用的算法,可以在WPF和UWP和Xamarin等上运行,基本上所有的.NET平台都能执行如下图,如果点在线段上,那么修改线段颜色假定有线段的定义如下publicrecordLine{publicPo......
  • (可持久化)权值线段树
    权值线段树就是把类型存在线段树上,每个下标存的是类型的数量。可以用来做离线的平衡树,如果值域范围小的话可以在线,只有一只\(\log\)。平衡树六种操作:插入\(x\)就是把\(x\)上的值加\(1\)。modify(1,1,n,x,1);删除一个\(x\)就是把\(x\)上的值加\(-1\)。modify(1,......
  • (nice!!!)LeetCode 2286. 以组为单位订音乐会的门票(线段树)
    题目:2286.以组为单位订音乐会的门票思路:线段树做法。(线段树)acwing1265.数星星classBookMyShow{public: //结构体typedefstructNode{intmn=0;//最小空位编号longlongsum=0;//非空位置之和}node; //n,mintN,M;......
  • 线段树进阶应用学习笔记(一)(2024.7.19)(2024.8.22)
    线段树优化建图算法流程复杂度分析例题一#include<bits/stdc++.h>usingnamespacestd;#defineintlonglongconstintN=5e5,M=5e6+9;structEdge{ intv,w,nex;}e[M];inthead[M],ecnt;voidAddEdge(intu,intv,intw){ e[++ecnt]=Edge{v,w,hea......