李超线段树(segment[HEOI2013]-洛谷T4097)
(neng了好久好久才糊弄懂得知识点...)
一、李超线段树
在线动态维护一个二维平面直角坐标系,
支持插入一条线段,
询问与直线x = x0相交的所有线段中,交点y的最大/小值
(若有多条线段符合条件,输出编号最小的线段的编号)
洛谷板子题-Segment[HEOI2013]-洛谷T4097
二、add操作
整个李超线段树的核心就是add操作
1.特判 l == r
已经到了一个点
如果该点之前没有维护线段,直接维护现在的线段
如果该点已经维护过,选择纵坐标靠上的直线(点),纵坐标相同,选择编号较小的
2.如果没有恰好放在区间里
如果不过mid,根据与mid关系左右查找
如果过mid,劈两半分别查找
3.如果找到了恰好的区间
如果该区间没有维护线段,维护该线段
如果有,
(1).如果中点处新的有,留下新的,把旧的中,稍大的一般留下(全劣则淘汰),下放到对应的子区间。
(2).如果中点处值相同。一般情况选择新的劈断的下放(省的建线段)。但是当新的编号较小,并且新的线段的右端点的纵坐标大于等于旧的,将旧的右半部分下放(使mid处一定取得的使新的线段,也就是编号较小的)
(3).如果中点处旧的优,同理...
//李超线段树
#include<cstdio>
#include<algorithm>
using namespace std;
inline int read()
{
int sum = 0,p = 1;
char ch = getchar();
while(ch < '0' || ch > '9')
{
if(ch == '-')
p = -1;
ch = getchar();
}
while(ch >= '0' && ch <= '9')
{
(sum *= 10) += ch - '0';
ch = getchar();
}
return sum * p;
}
#define mid ((l + r)>>1)
#define lson l,mid,o<<1
#define rson mid + 1,r,o<<1|1
const int mod1 = 39989,mod2 = 1e9,N = 50100;;
int n,ans,lastans,id;//ans实际答案,lastans上次查询的答案,id给函数编的号
int sx1[N << 2],sx2[N << 2],sy1[N << 2],sy2[N << 2],sum[N << 2];
bool vis[N << 2];
double tval;
//求节点储存的原函数的o点的值
double G(int o,int x1,int y1,int x2,int y2)
{
if(x1 == x2)
return y2;
else
return 1.0 *(o - x2) *(y1 - y2)/(x1 - x2) +y2;
}
//当新加入的函数是一条垂直于x轴的直线时 的修改操作
void change(int x,int v,int tot,int l,int r,int o)
{
if(l == r)
{
if(!vis[o])
{
sx1[o] = sx2[o] = l;
sy1[o] = sy2[o] = v;
sum[o] = tot;
vis[o] = true;
}
else
{
double cnt = G(x,sx1[o],sy1[o],sx2[o],sy2[o]);
if(cnt > v || (cnt == v && tot < sum[o]))
{
sx1[o] = sx2[o] = l;
sy1[o] = sy2[o] = v;
sum[o] = tot;
}
}
return;
}
if(mid >= x)
change(x,v,tot,lson);
else
change(x,v,tot,rson);
}
//求两个函数的交点
double Inter(double x1,double y1,double x2,double y2,double x3,double y3,double x4,double y4)
{
double a,b,c,d,g,h,f,t,s;
a = x2 - x1;
b = x3 - x4;
c = y2 - y1;
d = y3 - y4;
g = x3 - x1;
h = y3 - y1;
f = a *d - b * c;
t = (d * g - b * h)/f;
return x1 +t * (x2 - x1);
}
void update(int ql,int qr,int x1,int y1,int x2,int y2,int tot,int l,int r,int o)
{
if(ql <= l && r <= qr)
{
if(!vis[o])
{
sx1[o] = x1,sy1[o] = y1,sx2[o] = x2,sy2[o] = y2;
sum[o] = tot;
vis[o] = true;
}
else
{
double f1,f2,f3,f4;
f1 = G(l,x1,y1,x2,y2);
f2 = G(l,sx1[o],sy1[o],sx2[o],sy2[o]);
f3 = G(r,x1,y1,x2,y2);
f4 = G(r,sx1[o],sy1[o],sx2[o],sy2[o]);
if(f1 <= f2 && f3 <= f4)
return;
else if(f1 >= f2 && f3 >= f4)
{
sx1[o] = x1,sy1[o] = y1,sx2[o] = x2,sy2[o] = y2;
sum[o] = tot;
}
else
{
double spot = Inter(x1,y1,x2,y2,sx1[o],sy1[o],sx2[o],sy2[o]);
if(f1 >= f2)
{
if(spot <= mid)
update(ql,qr,x1,y1,x2,y2,tot,lson);
else
{
update(ql,qr,sx1[o],sy1[o],sx2[o],sy2[o],sum[o],rson);
sx1[o] = x1,sy1[o] = y1,sx2[o] = x2,sy2[o] = y2;
sum[o] = tot;
}
}
else
{
if(spot > mid)
update(ql,qr,x1,y1,x2,y2,tot,rson);
else
{
update(ql,qr,sx1[o],sy1[o],sx2[o],sy2[o],sum[o],lson);
sx1[o] = x1,sy1[o] = y1,sx2[o] = x2,sy2[o] = y2;
sum[o] = tot;
}
}
}
}
return;
}
if(ql <= mid)
update(ql,qr,x1,y1,x2,y2,tot,lson);
if(qr > mid)
update(ql,qr,x1,y1,x2,y2,tot,rson);
}
void query(int x,int l,int r,int o)
{
if(vis[o])
{
double cnt = G(x,sx1[o],sy1[o],sx2[o],sy2[o]);
if(cnt > tval || cnt == tval && sum[o] < ans)
{
tval = cnt;
ans = sum[o];
}
}
if(l == r)
return;
if(mid >= x)
query(x,lson);
else
query(x,rson);
}
int main()
{
n = read();
while(n--)
{
int opt = read();
if(!opt)
{
int x = read();
x = (x + lastans - 1)%mod1 + 1;
ans = 0;
tval = 0;
query(x,1,50000,1);
printf("%d\n",ans);
lastans = ans;
}
else
{
int x1 = read(),y1 = read(),x2 = read(),y2 = read();
x1 = (x1 + lastans - 1)%mod1 + 1;
y1 = (y1 + lastans - 1)%mod2 + 1;
x2 = (x2 + lastans - 1)%mod1 + 1;
y2 = (y2 + lastans - 1)%mod2 + 1;
if(x1 > x2)
{
swap(x1,x2);
swap(y1,y2);
}
if(x1 == x2)
change(x1,max(y1,y2),++id,1,50000,1);
else
update(x1,x2,x1,y1,x2,y2,++id,1,50000,1);
}
}
return 0;
}