BZOJ3165: [Heoi2013]Segment【李超线段树】

3165: [Heoi2013]Segment

李超线段树板子题。

对一次函数进行分治处理。

#include<cstdio>
#include<algorithm>
#define EXP 1e-8
#define N9 1000000000
using namespace std;
const int MAXN=100005;
struct Seg{
	double K,B;int id;
	double f(int x){return K*x+B;}
};
int n,Ans;
#include<cctype>
int read(){
	int ret=0;char ch=getchar();bool f=1;
	for(;!isdigit(ch);ch=getchar()) f^=!(ch^'-');
	for(; isdigit(ch);ch=getchar()) ret=(ret<<1)+(ret<<3)+ch-48;
	return f?ret:-ret;
}
struct LC_Tree{
	Seg Tre[MAXN<<2];bool vis[MAXN<<2];
	void PushDown(int rt,int L,int R,Seg p){
		if(!vis[rt]) return (void)(vis[rt]=1,Tre[rt]=p);
		double L1=p.f(L),R1=p.f(R),L2=Tre[rt].f(L),R2=Tre[rt].f(R);
		if(L2>=L1&&R2>=R1) return;
		if(L2<=L1&&R2<=R1) return (void)(Tre[rt]=p);
		double pos=(p.B-Tre[rt].B)/(Tre[rt].K-p.K);
		int mid=(R+L)>>1;
		if(pos<=mid) PushDown(rt<<1,L,mid,R1>R2?Tre[rt]:p);
		else PushDown(rt<<1|1,mid+1,R,L1>L2?Tre[rt]:p);
		if((L1>L2&&pos>=mid)||(R1>R2&&pos<mid)) Tre[rt]=p;
	}
	void Insert(int rt,int L,int R,int l,int r,Seg p){
		if(l<=L&&R<=r) return (void)(PushDown(rt,L,R,p));
		int mid=(R+L)>>1;
		if(l<=mid) Insert(rt<<1,L,mid,l,r,p);
		if(r>mid) Insert(rt<<1|1,mid+1,R,l,r,p);
	}
	double _abs(double x){return x<0?-x:x;}
	Seg Query(int rt,int L,int R,int p){
		if(L==R) return vis[rt]?Tre[rt]:(Seg){0,0,0};
		int mid=(L+R)>>1;Seg now=(Seg){0,0,0};
		if(p<=mid) now=Query(rt<<1,L,mid,p);
		else now=Query(rt<<1|1,mid+1,R,p);
		if(!vis[rt]) return now;
		double p1=Tre[rt].f(p),p2=now.f(p);
		if(!now.id||p1>p2||(_abs(p1-p2)<EXP&&Tre[rt].id<now.id)) return Tre[rt];
		else return now;
	}
}T;
int main(){
	n=read();
	for(int i=1,tot=0;i<=n;i++){
		int Type=read();
		if(Type){
			int x=(read()+Ans-1)%39989+1,y=(read()+Ans-1)%N9+1,_x=(read()+Ans-1)%39989+1,_y=(read()+Ans-1)%N9+1;
			if(x>_x) swap(x,_x),swap(y,_y);
			if(x==_x) T.Insert(1,1,39989,x,_x,(Seg){0.0,max(y,_y),++tot});
			else{
				double k=1.0*(1.0*y-_y)/(x-_x),b=1.0*y-k*x;
				T.Insert(1,1,39989,x,_x,(Seg){k,b,++tot});
			}
		}else{
			int x=(read()+Ans-1)%39989+1;
			printf("%d\n",Ans=T.Query(1,1,39989,x).id);
		}
	}
	return 0;
} 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值