BZOJ3165[Heoi2013]Segment——李超线段树
题目描述
要求在平面直角坐标系下维护两个操作:
1.在平面上加入一条线段。记第i条被插入的线段的标号为i。
2.给定一个数k,询问与直线 x = k相交的线段中,交点最靠上的线段的编号。
输入
第一行一个整数n,表示共n 个操作。
接下来n行,每行第一个数为0或1。
若该数为 0,则后面跟着一个正整数 k,表示询问与直线
x = ((k +lastans–1)%39989+1)相交的线段中交点(包括在端点相交的情形)最靠上的线段的编号,其中%表示取余。若某条线段为直线的一部分,则视作直线与线段交于该线段y坐标最大处。若有多条线段符合要求,输出编号最小的线段的编号。
若该数为 1,则后面跟着四个正整数 x0, y0, x 1, y 1,表示插入一条两个端点为
((x0+lastans-1)%39989+1,(y0+lastans-1)%10^9+1)和((x
1+lastans-1)%39989+1,(y1+lastans-1)%10^9+1) 的线段。
其中lastans为上一次询问的答案。初始时lastans=0。
输出
对于每个 0操作,输出一行,包含一个正整数,表示交点最靠上的线段的编号。若不存在与直线相交的线段,答案为0。
样例输入
1 8 5 10 8
1 6 7 2 6
0 2
0 9
1 4 7 6 7
0 5
样例输出
0 3
提示
对于100%的数据,1 ≤ n ≤ 10^5 , 1 ≤ k, x0, x1 ≤ 39989, 1 ≤ y0 ≤ y1 ≤ 10^9。
模板题,线段树上每个点存覆盖整个区间的最优线段。对于每条输入线段如果完全覆盖当前区间就进行以下判断,否则看它在左右子区间是否有覆盖的部分递归下去。对于完全覆盖当前区间分四种情况讨论:
1、当前区间无线段覆盖,直接将新线段存起来
2、当前区间存的线段完全覆盖新线段,直接返回
3、新线段完全覆盖当前区间存的线段,将新线段存起来
4、当前区间存的线段和新线段相交,将区间中点处更高的存为当前区间的线段,并将另一条线段向它左右两端较高的那端的子区间递归下去
查询时只要将查询路径上所有线段取最高的那个即可。
#include<set> #include<map> #include<queue> #include<stack> #include<cmath> #include<cstdio> #include<vector> #include<bitset> #include<cstring> #include<iostream> #include<algorithm> #define ll long long #define eps 1e-8 using namespace std; int num[200010]; double k[100010]; double b[100010]; int n; int opt; int cnt; int ans; int X0,Y0,X1,Y1; bool cmp(double x) { return fabs(x)<=eps; } double f(int id,int x) { return k[id]*x+b[id]; } bool judge(int idx,int idy,int x) { double fx=f(idx,x); double fy=f(idy,x); return cmp(fx-fy)?idx<idy:fx<fy; } void change(int rt,int l,int r,int L,int R,int id) { int mid=(l+r)>>1; if(L<=l&&r<=R) { if(judge(id,num[rt],l)&&judge(id,num[rt],r)) { return ; } if(judge(num[rt],id,l)&&judge(num[rt],id,r)) { num[rt]=id; return ; } if(judge(num[rt],id,mid)) { swap(num[rt],id); } if(judge(num[rt],id,l)) { change(rt<<1,l,mid,L,R,id); } else { change(rt<<1|1,mid+1,r,L,R,id); } return ; } if(L<=mid) { change(rt<<1,l,mid,L,R,id); } if(R>mid) { change(rt<<1|1,mid+1,r,L,R,id); } } int query(int rt,int l,int r,int x) { if(l==r) { return num[rt]; } int mid=(l+r)>>1; int res=x<=mid?query(rt<<1,l,mid,x):query(rt<<1|1,mid+1,r,x); if(judge(res,num[rt],x)) { res=num[rt]; } return res; } int main() { ans=-1; scanf("%d",&n); for(int i=1;i<=n;i++) { scanf("%d",&opt); if(opt) { scanf("%d%d%d%d",&X0,&Y0,&X1,&Y1); cnt++; X0=(X0+ans+39989)%39989+1,Y0=(1ll*Y0+ans+1000000000)%1000000000+1; X1=(X1+ans+39989)%39989+1,Y1=(1ll*Y1+ans+1000000000)%1000000000+1; if(X1<X0) { swap(X1,X0); swap(Y1,Y0); } if(X1==X0) { k[cnt]=0; b[cnt]=max(Y0,Y1); } else { k[cnt]=(double)(Y1-Y0)/(X1-X0); b[cnt]=Y1-k[cnt]*X1; } change(1,1,40000,X0,X1,cnt); } else { scanf("%d",&X0); X0=(X0+ans+39989)%39989+1; ans=query(1,1,40000,X0); printf("%d\n",ans); ans--; } } }