【[HEOI2013]Segment 】李超线段树MOBAN
简单来说李超树就是利用线段树的永久化标记来维护一个平面的若干线段组成的凸壳
(moban无讲解)
luogu4097
题目描述
要求在平面直角坐标系下维护两个操作: 在平面上加入一条线段。记第 i 条被插入的线段的标号为 i 给定一个数 k,询问与直线 x = k 相交的线段中,交点最靠上的线段的编号。输入输出格式
输入格式:
第一行一个整数 n,表示共 n 个操作 接下来 n 行,每行第一个数为 0 或 1 若该数为 0,则后面跟着一个正整数 k,表示询问与直线 x = ((k + lastans – 1)%39989+1)相交的线段中交点(包括在端点相交的情形)最靠上的线段的编号,其中%表示取余。若某条线段为直线的一部分,则视作直线与线段交于该线段 y 坐标最大处。若有多条线段符合要求,输出编号最小的线段的编号 若该数为 1,则后面跟着四个正整数 x0, y0, x1, y1,表示插入一条两个端点为 ((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输出格式:
对于每个 0 操作,输出一行,包含一个正整数,表示交点最靠上的线段的编 号。若不存在与直线相交的线段,答案为 0输入输出样例
输入样例#1:
6
1 8 5 10 8
1 6 7 2 6
0 2
0 9
1 4 7 6 7
0 5
输出样例#1:
2
0
3
说明
对于 30%的数据,n ≤ 1000 对于 100%的数据,1 ≤ n ≤ 10^5, 1 ≤ k, x0, x1 ≤ 39989, 1 ≤ y0 ≤ y1 ≤ 10^9 就是一个模板。利用一个线段覆盖区间的一段的话,递归下去改,如果被线段上原本的线段爆踩了或者爆踩了别的,就返回或者直接代替。否则的话,就看哪个占了一半多,占了一半多的保留,然后把另外一个递归到一边下去。 时间复杂度$O(nlog^2n)$实际上快很多 code:#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#define pr pair<db,int>
using namespace std;
const int maxn = 80005;
typedef double db ;
struct line { db k,b; int id; };
struct node{
node *ls,*rs;
bool tag; line o;
}z[maxn],*rt; int tot;
int n,cnt;
void pushdown(node *&p,int l,int r,line oo) {
if(!p->tag) p->tag = 1 , p->o = oo;
db l0 = oo.k*l + oo.b; db r0 = oo.k*r + oo.b;
db l1 = p->o.k*l + p->o.b; db r1 = p->o.k*r + p->o.b;
if(l1>=l0&&r1>=r0) return;
if(l0>=l1&&r0>=r1) { p->o = oo; return; }
if(l==r) return;
int mid = (l+r)>>1;
db pos = (oo.b-p->o.b)/(p->o.k-oo.k);
if(pos<=mid) pushdown(p->ls,l,mid,l0>l1?oo:p->o);
else pushdown(p->rs,mid+1,r,r0>r1?oo:p->o);
if((pos>mid&&(l0>l1))||(pos<=mid&&(r0>r1))) p->o = oo;
}
void addseg(node *&p,int l,int r,int x,int y,line oo) {
if(x<=l&&r<=y) {
pushdown(p,l,r,oo);
return;
}
int mid = (l+r)>>1;
if(y<=mid) addseg(p->ls,l,mid,x,y,oo);
else if(x>mid) addseg(p->rs,mid+1,r,x,y,oo);
else addseg(p->ls,l,mid,x,y,oo),addseg(p->rs,mid+1,r,x,y,oo);
}
pr query(node *&p,int l,int r,int x) {
if(l==r) {
if(!p->tag)return pr(0,0);
else return pr(p->o.k*x+p->o.b,p->o.id);
}
int mid = (l+r)>>1;
pr yo = pr(p->o.k*x+p->o.b,p->o.id);
if(x<=mid) yo = max(yo,query(p->ls,l,mid,x));
else yo = max(yo,query(p->rs,mid+1,r,x));
return yo;
}
void maketree(node *&p,int l,int r) {
p = &z[++tot];
if(l==r) return;
int mid = (l+r)>>1;
maketree(p->ls,l,mid); maketree(p->rs,mid+1,r);
}
int main() {
scanf("%d",&n);
int lstans = 0;
maketree(rt,1,39989);
for(int i=1;i<=n;i++) {
int opt; scanf("%d",&opt);
if(opt==0) {
int x;
scanf("%d",&x);
x = ( x + lstans - 1 )%39989+1;
lstans = query(rt,1,39989,x).second;
printf("%d\n",lstans);
} else {
int xa,ya,xb,yb;
scanf("%d%d%d%d",&xa,&ya,&xb,&yb);
xa = (xa+lstans-1)%39989+1; xb = (xb+lstans-1)%39989+1;
ya = (ya+lstans-1)%((int)1e9)+1; yb = (yb+lstans-1)%((int)1e9)+1;
if(xa==xb) addseg(rt,1,39989,xa,xb,(line){0,1.0*max(ya,yb),++cnt} );
else {
if(xa>xb) swap(xa,xb),swap(ya,yb);
db kk = 1.0*(yb-ya)/(xb-xa);
addseg(rt,1,39989,xa,xb,(line){kk,ya-kk*xa,++cnt});
}
}
}
}