洛谷傳送門
BZOJ傳送門
題目描述
要求在平面直角座標系下維護兩個操作:
- 在平面上加入一條線段。記第 條被插入的線段的標號爲
- 給定一個數 ,詢問與直線 相交的線段中,交點最靠上的線段的編號。
輸入輸出格式
輸入格式:
第一行一個整數 ,表示共 個操作
接下來 行,每行第一個數爲 或
若該數爲 ,則後面跟着一個正整數 ,表示詢問與直線 相交的線段中交點(包括在端點相交的情形)最靠上的線段的編號,其中%表示取餘。若某條線段爲直線的一部分,則視作直線與線段交於該線段 y 座標最大處。若有多條線段符合要求,輸出編號最小的線段的編號
若該數爲 ,則後面跟着四個正整數 ,表示插入一條兩個端點爲 和 的線段
其中 爲上一次詢問的答案。初始時
輸出格式:
對於每個 操作,輸出一行,包含一個正整數,表示交點最靠上的線段的編 號。若不存在與直線相交的線段,答案爲
輸入輸出樣例
輸入樣例#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
說明
對於 的數據,
對於 的數據,
解題分析
李超線段樹板題。
對於一個區間, 我們維護在位置最高的那條線段。
更新時如果在新加入的線段比原來的線段更劣或更優, 就直接覆蓋或return。
否則留下中間更高的那個線段, 然後將更低的那條較高的一端下放更新。
這樣每條線段會對應個區間, 下放的複雜度是, 所以總複雜度。
注意有平行於軸的線段, 這種情況直接將函數表達式改成最高的那個點。
代碼如下:
#include <cstdio>
#include <cstring>
#include <cmath>
#include <cstdlib>
#include <cctype>
#include <algorithm>
#define R register
#define IN inline
#define W while
#define gc getchar()
#define db double
#define ls (now << 1)
#define rs (now << 1 | 1)
#define MX 100500
#define MOD 1000000000
#define EPS 1e-8
template <class T>
IN void in(T &x)
{
x = 0; R char c = gc;
for (; !isdigit(c); c = gc);
for (; isdigit(c); c = gc)
x = (x << 1) + (x << 3) + c - 48;
}
template <class T> IN T max(T a, T b) {return a > b ? a : b;}
template <class T> IN T min(T a, T b) {return a < b ? a : b;}
template <class T> IN T abs(T a) {return a > 0 ? a : -a;}
int n, lastans = -1, tot;
struct Node {int id; bool use;} tree[MX << 1];
struct Line {db k, b;} line[MX];
IN db f(R int id, R int x) {return line[id].k * x + line[id].b;}
IN bool better(R int x, R int y, R int pos)
{
db fx = f(x, pos), fy = f(y, pos);
if (abs(fx - fy) < EPS) return x < y;
else return fx > fy;
}
void insert(R int now, R int lef, R int rig, R int lb, R int rb, R int id)
{
if (rb < lef || lb > rig) return;
int mid = lef + rig >> 1;
if (lb <= lef && rb >= rig)
{
if (better(id, tree[now].id, lef) && better(id, tree[now].id, rig))
return tree[now].id = id, void();
if (better(tree[now].id, id, lef) && better(tree[now].id, id, rig))
return;
if (better(id, tree[now].id, mid)) std::swap(tree[now].id, id);
if (better(id, tree[now].id, lef)) insert(ls, lef, mid, lef, rig, id);
else insert(rs, mid + 1, rig, lef, rig, id);
return;
}
insert(ls, lef, mid, lb, rb, id);
insert(rs, mid + 1, rig, lb, rb, id);
}
int query(R int now, R int lef, R int rig, R int tar)
{
if (lef == rig) return tree[now].id;
int mid = lef + rig >> 1, ret;
if (tar <= mid)
{
ret = query(ls, lef, mid, tar);
return better(ret, tree[now].id, tar) ? ret : tree[now].id;
}
else
{
ret = query(rs, mid + 1, rig, tar);
return better(ret, tree[now].id, tar) ? ret : tree[now].id;
}
}
int main(void)
{
in(n);
int lx, ly, rx, ry, typ, pos;
for (R int i = 1; i <= n; ++i)
{
in(typ);
if (typ & 1)
{
in(lx), in(ly), in(rx), in(ry);
lx = (lx + lastans + 39989) % 39989 + 1;
ly = (ly + lastans + MOD) % MOD + 1;
rx = (rx + lastans + 39989) % 39989 + 1;
ry = (ry + lastans + MOD) % MOD + 1;
++tot;
if (lx > rx) std::swap(lx, rx), std::swap(ly, ry);
if (lx == rx) line[tot] = {0, max(ly, ry)};
else line[tot].k = 1.0 * (ry - ly) / (rx - lx), line[tot].b = ly - lx * line[tot].k;
insert(1, 1, 40000, lx, rx, tot);
}
else
{
in(pos);
pos = (pos + lastans + 39989) % 39989 + 1;
lastans = query(1, 1, 40000, pos);
printf("%d\n", lastans);
lastans--;
}
}
}