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

李超线段树

时间:2023-12-05 22:13:44浏览次数:33  
标签:kd int 线段 tree 李超 lastans ans

问题
洛谷P4097
在平面直角坐标系维护两个操作:
1.加入一条线段。
2.求目前平面直角坐标系中截一条直线\(x=k\)中与线段交点\(y\)最大的是那一条线段。
解决
李超线段树模板。
首先建一个以\(x\)为区间的线段树。
和普通线段树的主要区别是在对懒标记的处理上,这里是是没有单独的下方标记操作的,当到达一段被覆盖区间时,如果新标记的左右端点的\(y\)值均大于旧标记的,则更新标记,返回,均小于就直接返回,一大一小就找两线段的交点,交点靠近的一端\(y\)值大的线段下放交点所在的那半边,剩余的那条留下做新标记。
修改复杂度是\(\Theta (\log_2^2 n)\)
代码:

#include<iostream>
using namespace std;
int kd(){
	int x=0,f=1;
	char a=getchar();
	while(a<'0'||a>'9'){
		if(a=='-'){
			f=-1;
		}
		a=getchar();
	}
	while(a>='0'&&a<='9'){
		x=x*10+a-'0';
		a=getchar();
	}
	return x*f;
}
int n;
struct node{
	int l,r;
	double lzl;
	double lzr;
	int id;
}tree[159956];
void build(int i,int l,int r){
	tree[i].l=l;
	tree[i].r=r;
	tree[i].lzl=0;
	tree[i].lzr=0;
	tree[i].id=0;
	if(l==r){
		return ;
	}
	int mid=(l+r)/2;
	build(i*2,l,mid);
	build(i*2+1,mid+1,r);
}
void add(int i,int l,int r,double x,double y,int p){
	if(tree[i].l==l&&tree[i].r==r){
		if(x==tree[i].lzl&&y==tree[i].lzr){
			tree[i].id=min(tree[i].id,p);
			return ;
		}
		if(x>tree[i].lzl&&y>tree[i].lzr){
			tree[i].lzl=x;
			tree[i].lzr=y;
			tree[i].id=p;
			return ;
		}
		if(x<tree[i].lzl&&y<tree[i].lzr){
			return ;
		}
		if(x>=tree[i].lzl){
			if(x-tree[i].lzl<=tree[i].lzr-y){
				add(i*2,tree[i*2].l,tree[i*2].r,x,x+(y-x)*1.0/(r-l)*(tree[i*2].r-tree[i*2].l),p);
			}
			else{
				swap(tree[i].lzl,x);
				swap(tree[i].lzr,y);
				swap(tree[i].id,p);
				add(i*2+1,tree[i*2+1].l,tree[i*2+1].r,y+(x-y)*1.0/(r-l)*(tree[i*2+1].r-tree[i*2+1].l),y,p);
			}
		}
		else{
			if(y-tree[i].lzr<tree[i].lzl-x){
				add(i*2+1,tree[i*2+1].l,tree[i*2+1].r,y+(x-y)*1.0/(r-l)*(tree[i*2+1].r-tree[i*2+1].l),y,p);
			}
			else{
				swap(tree[i].lzl,x);
				swap(tree[i].lzr,y);
				swap(tree[i].id,p);
				add(i*2,tree[i*2].l,tree[i*2].r,x,x+(y-x)*1.0/(r-l)*(tree[i*2].r-tree[i*2].l),p);
			}
		}
		return ;
	}
	if(tree[i*2].r>=r){
		add(i*2,l,r,x,y,p);
		return ;
	}
	if(tree[i*2+1].l<=l){
		add(i*2+1,l,r,x,y,p);
		return ;
	}
	add(i*2,l,tree[i*2].r,x,x+(y-x)*1.0/(r-l)*(tree[i*2].r-l),p);
	add(i*2+1,tree[i*2+1].l,r,y+(x-y)*1.0/(r-l)*(r-tree[i*2+1].l),y,p);
}
struct nod{
	double maxn;
	int id;
}ans;
void search(int i,int p){
	if(tree[i].l==tree[i].r){
		double x=tree[i].lzl;
		if(x>ans.maxn||(x==ans.maxn&&tree[i].id<ans.id)){
			ans.maxn=x;
			ans.id=tree[i].id;
		}
		return ;
	}
	double x=tree[i].lzl+(tree[i].lzr-tree[i].lzl)*1.0/(tree[i].r-tree[i].l)*(p-tree[i].l);
	if(x>ans.maxn||(x==ans.maxn&&tree[i].id<ans.id)){
		ans.maxn=x;
		ans.id=tree[i].id;
	}
	if(tree[i*2].r>=p){
		search(i*2,p);
	}
	else{
		search(i*2+1,p);
	}
}
int lastans=0;
int main(){
	cin>>n;
	build(1,1,39989);
	int cnt=0;
	while(n--){
		int opt;
		opt=kd();
		if(opt==1){
			cnt++;
			int x_1,x_2;
			int y_1,y_2;
			x_1=kd();y_1=kd();x_2=kd();y_2=kd();
			x_1=(x_1+lastans-1)%39989+1;
			y_1=(y_1+lastans-1)%1000000000+1;
			x_2=(x_2+lastans-1)%39989+1;
			y_2=(y_2+lastans-1)%1000000000+1;
			if(x_1==x_2){
				y_1=max(y_1,y_2);
				y_2=max(y_1,y_2);
			}
			if(x_1>x_2){
				swap(x_1,x_2);
				swap(y_1,y_2);
			}
			add(1,x_1,x_2,y_1,y_2,cnt);
		}
		if(opt==0){
			int k=kd();
			k=(k+lastans-1)%39989+1;
			ans.maxn=0;
			ans.id=0;
			search(1,k);
			printf("%d\n",ans.id);
			lastans=ans.id;
		}
	}
	return 0;
}

标签:kd,int,线段,tree,李超,lastans,ans
From: https://www.cnblogs.com/z-2-we/p/17878415.html

相关文章

  • 线段树优化建图
    问题:CF786B给定一个\(n\)个点,\(m\)次连边的有向图,有三种连边(均有边权)方式:1.\(u\tov\),一条\(u\)指向\(v\)的连边。2.\(u\to[l,r]\),\(u\)向在区间\([l,r]\)的点分别连一条边。3.\([l,r]\tov\),在区间\([l,r]\)的点向\(v\)分别连一条边。问从\(1\)点出发,到各个点的最短路。......
  • 像使用stl一样使用线段树 ——AtCoder Library(转载https://zhuanlan.zhihu.com/p/459
    地址:https://zhuanlan.zhihu.com/p/459579152 我这里翻译一下官方的文档。首先需要满足几个性质。(注意 ∗ 是个操作,不是单纯的一个乘号)1)操作满足结合律即 (a∗b)∗c=a∗(b∗c)2)操作需要有个幺元(基本元/单位元)a∗e=e∗a=a如果你有这个一个序列S,长度为N ,接下......
  • 【2024省选冲刺计划】数据结构相关-线段树进阶
    线段树进阶0x01李超线段树FZPJ4519[2021冬令营模拟]上古遗迹【题目背景】“沙……沙……沙……”独行者的脚步一次次被刻进沙漠中,干冷的风携沙尘在男子的四围穿过。“该死……这沙尘什么时候才能消停会儿……”男子止不住地咳嗽,随即停了下来,开始查看便携式投影设备上的信......
  • 树状数组和线段树
    树状数组:1.将某一个数加上k2.求出某区间每一个数的和#include<bits/stdc++.h>usingnamespacestd;typedeflonglongll;lln,m,a[500000+10];lllowbit(llx){returnx&(-x);}voidadd(llx,llk){ while(x<=n){ a[x]+=k; x+=lowbit(x); }}llquery(llx){ ll......
  • 线段树优化建图
    CF786B题意:定义\((u,v,w)\)表示\(u\)向\(v\)连了边权为\(w\)的边。有三种连边操作\((u,v,w)\)\(\foralli\in[l,r],(u,i,w)\)\(\foralli\in[l,r],(i,u,w)\)求最短路。暴力加边是\(O(nm)\)的,考虑优化。可以把图建到线段树上,线段树每个结点向左右儿子连\(w......
  • 【刷题记录】20231124 线段树分治
    做题记录:注意到每次相当于\(0\)后面加\(1\),\(1\)后面加\(0\),因此每次可以合并01和10然后将问题规模减半。黑白染色,白格子=lcm+1,黑格子=prime相乘。发现横着竖着有六个质数,斜着只用四个质数。调整一下顺序即可。状压DP。考虑S作为前缀max时S与U-S的排列方案数。S每......
  • 交点 - 求两线段交点2
    效果 会用到的知识相交-两线段是否相交-yanghui01-博客园(cnblogs.com)线性代数-已知点求直线方程-yanghui01-博客园(cnblogs.com)交点-两直线交点-yanghui01-博客园(cnblogs.com) //两线段是否相交publicstaticboolIsTwoSegmentIntersect2(V......
  • 「线段树」笔记
    基础建树voidbuild(intp,intl,intr){ t[p]=(tree){l,r,0}; if(l==r) { t[p].sum=val[l]; return; } intmid=(l+r)>>1; build(lp,l,mid); build(rp,mid+1,r); pushup(p);}单点修改(和)voidupdate(intp,intx,intk){ if(t[......
  • 【模板】可持久化线段树 2
    【模板】可持久化线段树2题目背景这是个非常经典的可持久化权值线段树入门题——静态区间第$k$小。数据已经过加强,请使用可持久化权值线段树。同时请注意常数优化。题目描述如题,给定$n$个整数构成的序列$a$,将对于指定的闭区间$[l,r]$查询其区间内的第$k$小值。输......
  • loj144&145 dfs序+树状数组/线段树
    https://loj.ac/p/144https://loj.ac/p/145两题非常相似,一题的权值修改是在点上的,一题的权值修改是在整棵子树上的。首先我们要了解dfs序,并记录每个节点的子树大小sz,对于一个节点,在dfs序上sz长的区间全都是他的子节点以及他自己。所以我们将一棵树映射到了一个区间上,并且可......