BZOJ3165: [Heoi2013]Segment
3165: [Heoi2013]Segment
Time Limit: 40 Sec Memory Limit: 256 MB
Submit: 939 Solved: 387
[Submit][Status][Discuss]
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)和((x
1+lastans-1)%39989+1,(y1+lastans-1)%10^9+1) 的线段。
其中lastans为上一次询问的答案。初始时lastans=0。
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
HINT
对于100%的数据,1 ≤ n ≤ 10^5 , 1 ≤ k, x0, x1 ≤ 39989, 1 ≤ y0 ≤ y1 ≤ 10^9。
Source
题解
李超线段树模板题。
李超线段树的思想大概是这样,每个节点都保留一个能够覆盖这个区间的线段,保证这个线段与区间内任何一个线段比较,都至少一半高于区间内的线段
对于新来的线段,如果线段包含区间,如果全部高于/低于区间内线段,就覆盖/不覆盖,否则按照交点分类递归下去。
如果交点在左边,那就递归左边,
交点在右边,就递归右边。
最多\(\log n\)层
至于当前节点保留原线段还是新来的线段,按照“保证这个线段与区间内任何一个线段比较,都至少一半高于区间内的线段”规则判断。
线段不包含区间那就像普通sgt一样递归即可,最多\(\log n\)层
复杂度\(O(n\log ^1 n)\)
注意线段垂直于x轴时,看做一个点即可。
要求输出编号最小的,通过修改和查询双重保证编号最小
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <map>
#include <cmath>
#define Pair std::pair<double, int>
inline void swap(int &x, int &y){int tmp = x;x = y;y = tmp;}
inline void read(int &x)
{
x = 0;char ch = getchar(), c = ch;
while(ch < '0' || ch > '9') c = ch, ch = getchar();
while(ch <= '9' && ch >= '0') x = x * 10 + ch - '0', ch = getchar();
if(c == '-') x = -x;
}
const int INF = 0x3f3f3f3f;
const int MAXN = 100000 + 10;
int max(int a, int b){return a > b ? a : b;}
double max(double a, double b){return a > b ? a : b;}
struct Line
{
double k, b;
int l, r, rank;
Line()
{
l = 1, r = 40000;
rank = k = b = 0;
}
Line(int x1, int y1, int x2, int y2, int _rank)
{
rank = _rank;
if(x1 > x2) swap(x1, x2), swap(y1, y2);
l = x1, r = x2;
if(x1 == x2)
{
k = 0;
b = max(y1, y2);
}
else
{
k = ((double)y1 - y2) / (x1 - x2);
b = (double)y1 - x1 * k;
}
}
double f(int x)
{
return k * x + b;
}
};
struct Node
{
int l, r;
Line line;
}node[MAXN << 2];
void build(int o = 1, int l = 1, int r = 40000)
{
node[o].l = l, node[o].r = r;
if(l == r) return;
int mid = (l + r) >> 1;
build(o << 1, l, mid);
build(o << 1 | 1, mid + 1, r);
}
void modify(Line L, int o = 1)
{
if(L.l <= node[o].l && node[o].r <= L.r)
{
if(L.f(node[o].l) <= node[o].line.f(node[o].l) &&
L.f(node[o].r) <= node[o].line.f(node[o].r)) return;
if(L.f(node[o].l) > node[o].line.f(node[o].l) &&
L.f(node[o].r) > node[o].line.f(node[o].r))
{
node[o].line = L;return;
}
double x = (node[o].line.b - L.b) / (L.k - node[o].line.k);
int mid = (node[o].l + node[o].r) >> 1;
if(x < mid)
{
if(L.f(node[o].r) > node[o].line.f(node[o].r))
modify(node[o].line, o << 1), node[o].line = L;
else modify(L, o << 1);
}
else
{
if(L.f(node[o].l) > node[o].line.f(node[o].l))
modify(node[o].line, o << 1 | 1), node[o].line = L;
else modify(L, o << 1 | 1);
}
return;
}
int mid = (node[o].l + node[o].r) >> 1;
if(L.l <= mid) modify(L, o << 1);
if(L.r > mid) modify(L, o << 1 | 1);
}
Pair max(Pair a, Pair b)
{
return a.first == b.first ? (b.second < a.second ? b : a) : (a.first < b.first ? b : a);
}
Pair ask(int pos, int o = 1)
{
if(node[o].l == node[o].r)
return std::make_pair(node[o].line.f(pos), node[o].line.rank);
Pair re = std::make_pair(node[o].line.f(pos), node[o].line.rank);
int mid = (node[o].l + node[o].r) >> 1;
if(pos <= mid) re = max(re, ask(pos, o << 1));
else re = max(re, ask(pos, o << 1 | 1));
return re;
}
int tot;
int main()
{
int lastans = 0, n;
read(n);
build();
for(int i = 1;i <= n;++ i)
{
int tmp;read(tmp);
if(tmp)
{
int tmp1, tmp2, tmp3, tmp4;
read(tmp1), read(tmp2), read(tmp3), read(tmp4);
tmp1 = (tmp1 + lastans - 1) % 39989 + 1;
tmp2 = (tmp2 + lastans - 1) % 1000000000 + 1;
tmp3 = (tmp3 + lastans - 1) % 39989 + 1;
tmp4 = (tmp4 + lastans - 1) % 1000000000 + 1;
modify(Line(tmp1, tmp2, tmp3, tmp4, ++ tot));
}
else
{
read(tmp);
tmp = (tmp + lastans - 1) % 39989 + 1;
printf("%d\n", lastans = ask(tmp).second);
}
}
return 0;
}