3165: [Heoi2013]Segment
Time Limit: 40 Sec Memory Limit: 256 MBSubmit: 465 Solved: 187
[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
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
0 3
HINT
对于100%的数据,1 ≤ n ≤ 10^5 , 1 ≤ k, x0, x1 ≤ 39989, 1 ≤ y0 ≤ y1 ≤ 10^9。
Source
线段树维护线段,23333
1 #include <bits/stdc++.h> 2 3 struct line 4 { 5 int lt, rt; 6 double k, b; 7 8 line(void) {}; 9 10 line(int x0, int y0, int x1, int y1) 11 { 12 if (x0 < x1) 13 lt = x0, rt = x1; 14 else 15 lt = x1, rt = x0; 16 17 if (x0 == x1) 18 { 19 k = 0.0; 20 b = y0 > y1 ? y0 : y1; 21 } 22 else 23 { 24 k = 1.0 * (y0 - y1) / (x0 - x1); 25 b = y0 - x0 * k; 26 } 27 } 28 29 inline double f(int x) 30 { 31 return k * x + b; 32 } 33 }ln[100005]; int tot; 34 35 int sg(double x) 36 { 37 static const double eps = 1e-10; 38 39 return (x > -eps) - (x < +eps); 40 } 41 42 int cross(int i, int j) 43 { 44 return floor((ln[i].b - ln[j].b) / (ln[j].k - ln[i].k)); 45 } 46 47 int flg[160005]; 48 49 int wi[40005]; double wy[40005]; 50 51 inline void update(int x, int p) 52 { 53 double y = ln[p].f(x); 54 55 int s = sg(y - wy[x]); 56 57 if (!wi[x] || s > 0 || (!s && p < wi[x])) 58 wi[x] = p, wy[x] = y; 59 } 60 61 void insert(int t, int l, int r, int p) 62 { 63 if (ln[p].lt <= l && ln[p].rt >= r) 64 { 65 if (!flg[t])flg[t] = p; 66 else 67 { 68 int mid = (l + r) >> 1; 69 70 bool lu = sg(ln[p].f(l) - ln[flg[t]].f(l)) > 0; 71 bool ru = sg(ln[p].f(r) - ln[flg[t]].f(r)) > 0; 72 73 if (lu && ru)flg[t] = p; 74 else if (lu || ru) 75 { 76 int tt = cross(p, flg[t]); 77 if (tt <= mid) 78 { 79 if (lu) 80 insert(t << 1, l, mid, p); 81 else 82 insert(t << 1, l, mid, flg[t]), flg[t] = p; 83 } 84 else 85 { 86 if (ru) 87 insert(t << 1 | 1, mid + 1, r, p); 88 else 89 insert(t << 1 | 1, mid + 1, r, flg[t]), flg[t] = p; 90 } 91 } 92 else 93 { 94 update(l, p); 95 update(r, p); 96 } 97 } 98 } 99 else 100 { 101 int mid = (l + r) >> 1; 102 103 if (ln[p].lt <= mid) 104 insert(t << 1, l, mid, p); 105 if (ln[p].rt > mid) 106 insert(t << 1 | 1, mid + 1, r, p); 107 } 108 } 109 110 int ansi; double ansy; 111 112 void query(int t, int l, int r, int x) 113 { 114 if (flg[t]) 115 { 116 double y = ln[flg[t]].f(x); 117 118 int s = sg(y - ansy); 119 120 if (s > 0 || (!s && flg[t] < ansi)) 121 ansi = flg[t], ansy = y; 122 } 123 124 if (l != r) 125 { 126 int mid = (l + r) >> 1; 127 128 if (x <= mid) 129 query(t << 1, l, mid, x); 130 if (x > mid) 131 query(t << 1 | 1, mid + 1, r, x); 132 } 133 } 134 135 signed main(void) 136 { 137 int n; scanf("%d", &n); 138 139 for (int ans = 0; n--; ) 140 { 141 int op; scanf("%d", &op); 142 143 if (op) // insert segment 144 { 145 int x0, y0, x1, y1; 146 147 scanf("%d%d%d%d", &x0, &y0, &x1, &y1); 148 149 x0 = (x0 + ans - 1) % 39989 + 1; 150 x1 = (x1 + ans - 1) % 39989 + 1; 151 y0 = (y0 + ans - 1) % 1000000000 + 1; 152 y1 = (y1 + ans - 1) % 1000000000 + 1; 153 154 ln[++tot] = line(x0, y0, x1, y1); 155 156 insert(1, 1, 40000, tot); 157 } 158 else // query segment 159 { 160 int x; scanf("%d", &x); 161 162 x = (x + ans - 1) % 39989 + 1; 163 164 ansi = wi[x], ansy = wy[x]; 165 166 query(1, 1, 40000, x); 167 168 printf("%d ", ans = ansi); 169 } 170 } 171 }
@Author: YouSiki