题解 P4097 【[HEOI2013]Segment 】
XG_Zepto
2018-04-25 11:01:28
### 思路
推广[个人博客](https://www.xgzepto.cn/post/bzoj-3165),CodeForces, AtCoder 经典题题解~~都没有~~
可以用线段树很方便地维护,对于每个区间,如果要加地线段在中点处更优,就替换原有的线段。
对于每条新加入的线段,我们需要用$log(n)$ 的复杂度将它分配到不同的区间内,对于每个区间,又要用$log(n)$的复杂度判断在所有子区间的优劣程度。
所以,插入复杂度是$log^2(n)$的,查询复杂度依然为$log(n)$。
### 代码实现
使用结构体$Node$存储每条线段的信息。
对于一条编号为$id$的线段,它的左端点是$(l,yl)$,而右端点是$(r,yr)$。判断交点的存在性和位置时,我们使用$Node.k$来获取这条线段的斜率。
在插入时,我们会不断调整新线段的左右端点位置以确保被当前区间覆盖,使用$Node.lm()$ / $Node.rm()$ 实现这个操作。
对于斜率不存在的线段要简单地特殊处理一下,我的插入方法能规避很多特判。
细节见注释。
```
#include <bits/stdc++.h>
#define ls (p<<1)
#define rs (p<<1|1)
#define maxn 100001
#define mid ((l+r)>>1)
using namespace std;
struct Node{
int l,r,id;
double yl,yr;
Node(int x1=0,int y1=0,int x2=0,int y2=0,int i=0){
l=x1,r=x2;yl=y1,yr=y2;id=i;
if (l==r) yl=yr=max(yl,yr);
}
double get(int x){return l==r?yl:yl+(k()*(x-l));}
double k(){return (yr-yl)/(r-l);}
void lm(int x){yl=get(x);l=x;}
void rm(int x){yr=get(x);r=x;}
};
bool hei(Node a,Node b,int x){
return a.get(x)==b.get(x)?a.id<b.id:a.get(x)>b.get(x);
}
struct St{
Node tree[maxn*4];
void build(int l,int r,int p){
tree[p].l=l,tree[p].r=r;
if (l==r) return;
build(l,mid,ls);
build(mid+1,r,rs);
}
Node query(int t,int l,int r,int p){
if (l==r) return tree[p];Node tem;
if (t<=mid) tem=query(t,l,mid,ls);
else tem=query(t,mid+1,r,rs);
return hei(tem,tree[p],t)?tem:tree[p];
}
void update(int l,int r,Node k,int p){
if (tree[p].l>k.l) k.lm(tree[p].l);
if (tree[p].r<k.r) k.rm(tree[p].r);
if (hei(k,tree[p],mid)) swap(tree[p],k);
if (min(tree[p].yl,tree[p].yr)>=max(k.yl,k.yr)) return;//如果在当前区间内没有交点就直接return
if (l==r) return;
if (tree[p].k()<=k.k()) update(mid+1,r,k,rs);//判断交点的位置
else update(l,mid,k,ls);
}
void insert(int l,int r,Node k,int p){
if (k.l>r||k.r<l) return;
if (tree[p].l>k.l) k.lm(tree[p].l);
if (tree[p].r<k.r) k.rm(tree[p].r);
if (l==k.l&&r==k.r) {update(l,r,k,p);return;}//被完美地覆盖才更新区间的信息
if (l==r) return;
insert(l,mid,k,ls);insert(mid+1,r,k,rs);
}
}T;
int la,Ind,n=39989;
int main(){
ios::sync_with_stdio(false);
T.build(1,n,1);
int m;cin>>m;
while(m--){
int temp;cin>>temp;
if (!temp){
int k;cin>>k;
k=(k+la-1)%39989+1;
la=T.query(k,1,n,1).id;
cout<<la<<endl;
}
else{
int x0,x1,y1,y0;
cin>>x0>>y0>>x1>>y1;
x0=(x0+la-1)%39989+1;x1=(x1+la-1)%39989+1;
y0=(y0+la-1)%1e9+1;y1=(y1+la-1)%1e9+1;//注意是1e9,而非题目所述的109
if (x0>x1) swap(x0,x1),swap(y0,y1);
Node tem=Node(x0,y0,x1,y1,++Ind);
T.insert(1,n,tem,1);
}
}
}
```