先我来说说李超线段树能干嘛: bzoj 3165
要求在平面直角坐标系下维护两个操作:
1. 在平面上加入一条线段。
2. 给定一个数 k ,询问与直线x=k 相交的线段中,交点最上的线段的编号。
3. 强制在线。
我们定义一个名称“较优线段”,表示在一个区间内有两条线段,从上面看哪一条直线占有较多的位置(即在区间中点处较高的线段)。
那怎么用线段树维护呢?
我们可以这样:
- 加入一条线段时,先找到该线段完全覆盖的区间,根据线段树的区间查询的复杂度可以知道最多有
logn
个区间;
- 若该区间没有线段,则加入该线段,返回;
- 若该区间有线段,则比较哪条线段为较优线段;
- 可以通过比较交点与区间中点的位置来判断;
- 将较优线段留下,另一条线段判断一下从上往下可以看到的线段位于区间中点的左边/右边,然后把它下传到左/右子区间,重复前一步;
- 查询时,和普通线段树一样,找到所在的位置,返回时对每个经过区间所要查询的位置计算一下高度,判断一下大小关系即可。
bzoj 3165
#include <cstdio>
#include <cstring>
#define Max(_A, _B) (_A > _B ? _A : _B)
#define Abs(_A) ((_A) > 0 ? _A : -(_A))
#define R register
#define eps 1e-9
int n, lastans;
struct Data{ int X0, X1; double Y0, Y1; int Id; } A[1 << 20], B[110];
double Calc(R int P, R Data t)
{
if(t.X0 == t.X1) return Max(t.Y0, t.Y1);
R double u = (t.Y1 - t.Y0) / (t.X1 - t.X0 + eps);
u = (double) (P - t.X0) * u + t.Y0;
return u;
}
template <class Au>
void Swap(R Au &A, R Au &B){ R Au t = A; A = B; B = t; }
void Updata(R int node, R int begin, R int end, R Data K)
{
if(begin > end) return ;
R int mid = begin + end >> 1;
if(K.X0 <= begin && end <= K.X1)
{
R double t1 = Calc(begin, K), t2 = Calc(end, K), t3 = Calc(begin, A[node]), t4 = Calc(end, A[node]);
if(!A[node].Id || ((t1 > t3) && (t2 > t4))) A[node] = K;
else if((t1 > t3) ^ (t2 > t4))
{
R double u = Calc(mid, K), v = Calc(mid, A[node]);
if(u > v)
{
Swap(A[node], K);
Swap(t1, t3);
Swap(t2, t4);
}
if(begin < end)
{
if(t3 < t1) Updata(node << 1, begin, mid, K);
else Updata(node << 1 | 1, mid + 1, end, K);
}
}
return ;
}
if(K.X0 <= mid) Updata(node << 1, begin, mid, K);
if(K.X1 > mid) Updata(node << 1 | 1, mid + 1, end, K);
}
double Tmp;
void Query(R int node, R int begin, R int end, R int Pos)
{
if(begin > end) return ;
if(begin == end)
{
lastans = A[node].Id, Tmp = Calc(Pos, A[node]);
return ;
}
R int mid = begin + end >> 1;
if(Pos <= mid) Query(node << 1, begin, mid, Pos);
else Query(node << 1 | 1, mid + 1, end, Pos);
R double t = Calc(Pos, A[node]);
if(t - eps > Tmp || (Abs(t - Tmp) < 1e-7 && A[node].Id < lastans)) Tmp = t, lastans = A[node].Id;
}
int main()
{
scanf("%d", &n);
R int cnt = 0;
for(R int i = 1; i <= n; i++)
{
R int opt;
scanf("%d", &opt);
if(opt)
{
R int X0, Y0, X1, Y1;
scanf("%d %d %d %d", &X0, &Y0, &X1, &Y1);
X0 = (X0 + lastans - 1) % 39989 + 1;
Y0 = (Y0 + lastans - 1) % 1000000000 + 1;
X1 = (X1 + lastans - 1) % 39989 + 1;
Y1 = (Y1 + lastans - 1) % 1000000000 + 1;
if(X0 > X1) Updata(1, 1, 39989, (Data){X1, X0, Y1, Y0, ++cnt});
else Updata(1, 1, 39989, (Data){X0, X1, Y0, Y1, ++cnt});
}
else
{
R int k;
scanf("%d", &k);
k = (k + lastans - 1) % 39989 + 1;
Tmp = 0;
Query(1, 1, 39989, k);
printf("%d\n", lastans);
}
}
return 0;
}