HEOI2013 Segment
传说中的“李超树”。
大意:给你若干线段,试求横坐标x上的最上方一条线段的编号。无则输出零。
解:用线段树维护。
插入的时候保存自己这个区间上可能成为最大值的线段,被抛弃的则看情况下放。
查询时从最底层向上查一路,沿途取得答案。
函数我用的是斜截式来存,脑残的把b写错了.....getY还传错参了。
调掉之后就一发AC!哈哈哈
1 #include <cstdio> 2 #include <algorithm> 3 #include <cmath> 4 const int N = 40005, M = 100010, INF = 0x3f3f3f3f; 5 const double eps = 1e-10; 6 7 struct SG { 8 double k, b; 9 int l, r; 10 }sg[M]; 11 12 inline double getY(int a, int x) { 13 SG t = sg[a]; 14 if(x < t.l || t.r < x || !a) { 15 return (double)(-INF); 16 } 17 if(fabs(t.k - INF) < eps) { 18 return t.b; 19 } 20 return t.k * x + t.b; 21 } 22 23 struct SegmentTree { 24 int ans[N << 2]; 25 26 void add(int L, int R, int v, int l, int r, int o) { 27 //printf("add : %d %d %d %d %d \n", L, R, v, l, r); 28 int mid = (l + r) >> 1; 29 if(L <= l && r <= R) { 30 if(!ans[o]) { /// no segment 31 ans[o] = v; 32 //printf("ans[] = %d \n", ans[o]); 33 return; 34 } 35 if(l == r) { /// only one 36 if(getY(v, r) > getY(ans[o], r)) { 37 ans[o] = v; 38 //printf("ans[] = %d \n", ans[o]); 39 } 40 return; 41 } 42 double A = getY(v, l), B = getY(v, mid), C = getY(v, r); 43 double D = getY(ans[o], l), E = getY(ans[o], mid), F = getY(ans[o], r); 44 if(A > D && C > F) { 45 ans[o] = v; 46 //printf("ans[] = %d \n", ans[o]); 47 return; 48 } 49 /*if(v == 3 && l == 4 && r == 5) { 50 printf("B = %lf E = %lf\n", B, D); 51 }*/ 52 if(!(A > D) && !(C > F)) { 53 return; 54 } 55 if(B > E) { 56 if(sg[v].k > sg[ans[o]].k) { 57 add(l, mid, ans[o], l, mid, o << 1); 58 ans[o] = v; 59 //printf("ans[] = %d \n", ans[o]); 60 } 61 else { 62 add(mid + 1, r, ans[o], mid + 1, r, o << 1 | 1); 63 ans[o] = v; 64 //printf("ans[] = %d \n", ans[o]); 65 } 66 } 67 else { 68 if(sg[v].k > sg[ans[o]].k) { 69 add(mid + 1, r, v, mid + 1, r, o << 1 | 1); 70 } 71 else { 72 add(l, mid, v, l, mid, o << 1); 73 } 74 } 75 return; 76 } 77 if(L <= mid) { 78 add(L, R, v, l, mid, o << 1); 79 } 80 if(mid < R) { 81 add(L, R, v, mid + 1, r, o << 1 | 1); 82 } 83 return; 84 } 85 int ask(int p, int l, int r, int o) { 86 if(l == r) { 87 //printf("ask: %d %d %d return %d \n", p, l, r, ans[o]); 88 return ans[o]; 89 } 90 int mid = (l + r) >> 1; 91 int A; 92 if(p <= mid) { 93 A = ask(p, l, mid, o << 1); 94 } 95 else { 96 A = ask(p, mid + 1, r, o << 1 | 1); 97 } 98 int t = ans[o]; 99 if(getY(A, p) - eps > getY(t, p)) { 100 t = A; 101 } 102 else if(fabs(getY(A, p) - getY(t, p)) < eps) { 103 t = std::min(t, A); 104 } 105 //printf("ask: %d %d %d return %d \n", p, l, r, t); 106 return t; 107 } 108 }SgT; 109 110 int main() { 111 int n, MO = 39989, lastans = 0, num = 0; 112 scanf("%d", &n); 113 for(int i = 1, f, x, xx, y, yy; i <= n; i++) { 114 scanf("%d", &f); 115 if(f) { 116 scanf("%d%d%d%d", &x, &y, &xx, &yy); 117 x = (x + lastans - 1) % MO + 1; 118 xx = (xx + lastans - 1) % MO + 1; 119 y = (y + lastans - 1) % 1000000000 + 1; 120 yy = (yy + lastans - 1) % 1000000000 + 1; 121 if(x > xx) { 122 std::swap(x, xx); 123 std::swap(y, yy); 124 } 125 sg[++num].l = x; 126 sg[num].r = xx; 127 if(x == xx) { 128 sg[num].k = 1.0 * INF; 129 sg[num].b = 1.0 * std::max(y, yy); 130 } 131 else { 132 sg[num].k = 1.0 * (y - yy) / (x - xx); 133 sg[num].b = y - sg[num].k * x; 134 } 135 SgT.add(x, xx, num, 1, MO, 1); 136 /*for(int i = 1; i <= 11; i++) { 137 SgT.ask(i, 1, MO, 1); 138 } 139 puts("");*/ 140 } 141 else { 142 scanf("%d", &x); 143 x = (x + lastans - 1) % MO + 1; 144 lastans = SgT.ask(x, 1, MO, 1); 145 printf("%d\n", lastans); 146 } 147 } 148 149 /*puts(""); 150 for(int i = 1; i <= num; i++) { 151 printf("%lf %lf %d %d \n", sg[i].k, sg[i].b, sg[i].l, sg[i].r); 152 }*/ 153 154 return 0; 155 }
调起来真难...很不理解为什么有人的李超树代码只有我的 1 / 3 长