BZOJ 3165: [Heoi2013]Segment

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。

Solution

线段树,每个线段上记录覆盖这个区间的所有线段中最上面的一条。

现在考虑在区间l,r中插入线段x:

如果x覆盖了区间l,r:

如果l,r中没有线段,那么更新l,r中的线段为x。

考察当前l,r中的线段y,如果x(l)、x(r)分别在y(l)、y(r)的上边,那么直接扔掉y,把l,r的答案改为x,如果都在下边,扔掉x。如果x与y相交了,考虑焦点位置与左右端点高度,如果交点在左边,x(l)>y(l),可见x对右区间无贡献,直接递归修改左孩子,如果交点在左边x(l)<y(l),显然右区间答案为x,因此交换x与y,l,r区间答案改为x,用y递归修改左区间。交点在右边同理。

如果x没有覆盖区间l,r:

如果x与左区间相交,递归修改左区间,如果x与右区间相交,递归修改右区间。

Code

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
#include <cstdio>
#include <algorithm>
using namespace std;
typedef long long LL;
const int INF = 1009999999;
const int N = 39989;
const int NN = 1000000000;
int Read() {
	int r = 0, k = 1; char c = getchar();
	for (; '0' > c || c > '9'; c = getchar()) if (c == '-') k = -1;
	for (; '0' <= c && c <= '9'; c = getchar()) r = r * 10 - '0' + c;
	return r * k;
}
int lstans = 0; double maxans;
const int maxn = 40000;
int id[maxn << 2], A[maxn << 2], B[maxn << 2], C[maxn << 2], D[maxn << 2];
int decodeX(int x) { return (x + lstans - 1) % N + 1; }
int decodeY(int y) { return (y + lstans - 1) % NN + 1; }
double calc(int x0, int y0, int x1, int y1, int pos) {
	return double(y0) + double(pos - x0) / double(x0 - x1) * double(y0 - y1);
}
double cross(int x0, int y0, int x1, int y1, int x2, int y2, int x3, int y3) {
	double k1 = double(y0 - y1) / double(x0 - x1),
		   b1 = double(y0) - double(x0 * double(y0 - y1)) / double(x0 - x1),
		   k2 = double(y2 - y3) / double(x2 - x3),
		   b2 = double(y2) - double(x2 * double(y2 - y3)) / double(x2 - x3);
	return (b2 - b1) / (k1 - k2);
}
void change(int now, int l, int r, int x0, int y0, int x1, int y1, int nid) {
	if (x0 <= l && r <= x1) {
		if (!id[now]) {
			id[now] = nid;
			A[now] = x0;
			B[now] = y0;
			C[now] = x1;
			D[now] = y1;
			return;
		}
		double l1 = calc(A[now], B[now], C[now], D[now], l),
			   r1 = calc(A[now], B[now], C[now], D[now], r),
			   l2 = calc(x0, y0, x1, y1, l),
			   r2 = calc(x0, y0, x1, y1, r);
		if (l2 <= l1 && r2 <= r1) return;
		if (l1 < l2 && r1 < r2) {
			id[now] = nid;
			A[now] = x0;
			B[now] = y0;
			C[now] = x1;
			D[now] = y1;
			return;
		}
		double crs = cross(A[now], B[now], C[now], D[now], x0, y0, x1, y1);
		int mid = (l + r) >> 1;
		if (crs <= double(mid)) {
			if (l1 < l2)
				change(now << 1, l, mid, x0, y0, x1, y1, nid);
			if (r1 < r2) {
				swap(A[now], x0);
				swap(B[now], y0);
				swap(C[now], x1);
				swap(D[now], y1);
				swap(id[now], nid);
				change(now << 1, l, mid, x0, y0, x1, y1, nid);
			}
		} else {
			if (r1 < r2)
				change(now << 1 | 1, mid + 1, r, x0, y0, x1, y1, nid);
			if (l1 < l2) {
				swap(A[now], x0);
				swap(B[now], y0);
				swap(C[now], x1);
				swap(D[now], y1);
				swap(id[now], nid);
				change(now << 1 | 1, mid + 1, r, x0, y0, x1, y1, nid);
			}
		}
		return;
	} else {
		int mid = (l + r) >> 1;
		if (x0 <= mid)
			change(now << 1, l, mid, x0, y0, x1, y1, nid);
		if (x1 > mid)
			change(now << 1 | 1, mid + 1, r, x0, y0, x1, y1, nid);
	}
}
void query(int now, int l, int r, int pos) {
	if (id[now]) {
		if (!lstans) {
			lstans = id[now];
			maxans = calc(A[now], B[now], C[now], D[now], pos);
		} else {
			double tmp = calc(A[now], B[now], C[now], D[now], pos);
			if (tmp > maxans) {
				lstans = id[now];
				maxans = calc(A[now], B[now], C[now], D[now], pos);
			}
		}
	}
	if (l == r) return;
	int mid = (l + r) >> 1;
	if (pos <= mid) query(now << 1, l, mid, pos);
	else query(now << 1 | 1, mid + 1, r, pos);
}
int main() {
	int m = Read();
	int a, b, c, d, e, i = 0;
	while (m--) {
		e = Read();
		if (e) {
			++i;
			a = decodeX(Read());
			b = decodeY(Read());
			c = decodeX(Read());
			d = decodeY(Read());
			if (a > c) {
				swap(a, c);
				swap(b, d);
			}
			change(1, 1, N, a, b, c, d, i);
		} else {
			a = decodeX(Read());
			lstans = 0;
			query(1, 1, N, a);
			printf("%d\n", lstans);
		}
	}
	return 0;
}