[HEOI2013]Segment
Description
要求在平面直角坐标系下维护两个操作:
1.在平面上加入一条线段。记第i条被插入的线段的标号为i。
2.给定一个数k,询问与直线 x = k相交的线段中,交点最靠上的线段的编号。
Input
第一行一个整数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)
和((x1+lastans-1)%39989+1,(y1+lastans-1)%10^9+1) 的线段。
其中lastans为上一次询问的答案。初始时lastans=0。
1 ≤ n ≤ 10^5 , 1 ≤ k, x0, x1 ≤ 39989, 1 ≤ y0 ≤ y1 ≤ 10^9。
Output
对于每个 0操作,输出一行,包含一个正整数,表示交点最靠上的线段的编号。
若不存在与直线相交的线段,答案为0。
Sample Input
6
1 8 5 10 8
1 6 7 2 6
0 2
0 9
1 4 7 6 7
0 5
Sample Output
2
0
3
标记永久化,不过这题插入的是一条条线段,其实也没什么关系,稍微判断下就好了。不过需要记得判断斜率无穷大,然后基本上就没啥了。
一道比这题简单点的题,[JSOI2008]Blue Mary开公司
两题基本相似,小细节自己画个图理解下就好
#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define inf 0x7f7f7f7f
using namespace std;
typedef long long ll;
typedef unsigned int ui;
typedef unsigned long long ull;
inline int read(){
int x=0,f=1;char ch=getchar();
for (;ch<'0'||ch>'9';ch=getchar()) if (ch=='-') f=-1;
for (;ch>='0'&&ch<='9';ch=getchar()) x=(x<<1)+(x<<3)+ch-'0';
return x*f;
}
inline void print(int x){
if (x>=10) print(x/10);
putchar(x%10+'0');
}
const int N=1e5,px=39989,py=1e9;
double K[N+10],B[N+10];
int n,lastans,cnt;
bool check(int x,int y,int pos){
if (!x) return 1;
double l1=K[x]*pos+B[x],l2=K[y]*pos+B[y];
return l1!=l2?l1<l2:x>y;
}
struct Segment{
#define ls (p<<1)
#define rs (p<<1|1)
int tree[N*4+10];
void insert(int p,int l,int r,int t){//判断和“Blue Mary开公司”稍有不同,不过读者们可以画个图,便可以马上理解了
if (!tree[p]) tree[p]=t;
if (check(tree[p],t,l)) swap(tree[p],t);
if (l==r||K[tree[p]]==K[t]) return;
double g=1.0*(B[tree[p]]-B[t])/(K[t]-K[tree[p]]);
if (g<l||g>r) return;
int mid=(l+r)>>1;
if (g<=mid) insert(ls,l,mid,tree[p]),tree[p]=t;
if (g>mid) insert(rs,mid+1,r,t);
}
int query(int p,int l,int r,int t){
if (l==r) return tree[p];
int mid=(l+r)>>1,ans;
if (t<=mid) ans=query(ls,l,mid,t);
if (t>mid) ans=query(rs,mid+1,r,t);
return check(tree[p],ans,t)?ans:tree[p];
}
}Tree;
void change(int p,int l,int r,int x,int y,int t){//由外部修改转移到线段树上修改
if (x<=l&&r<=y){Tree.insert(p,l,r,t);return;}
int mid=(l+r)>>1;
if (x<=mid) change(p<<1,l,mid,x,y,t);
if (y>mid) change(p<<1|1,mid+1,r,x,y,t);
}
int main(){
n=read(),lastans=0;
for (int i=1;i<=n;i++){
int t=read();
if (t){
cnt++;
int x1=read(),y1=read(),x2=read(),y2=read();
x1=(x1+lastans-1)%px+1,y1=(y1+lastans-1)%py+1;
x2=(x2+lastans-1)%px+1,y2=(y2+lastans-1)%py+1;
if (x1>x2) swap(x1,x2),swap(y1,y2);
if (x1==x2) K[cnt]=0,B[cnt]=max(y1,y2);
else{
K[cnt]=1.0*(y2-y1)/(x2-x1);
B[cnt]=1.0*y1-K[cnt]*x1;
}
change(1,1,N,x1,x2,cnt);
}else{
int x=(read()+lastans-1)%px+1;
lastans=Tree.query(1,1,N,x);
printf("%d\n",lastans);
}
}
return 0;
}