P4097 [HEOI2013]Segment(李超树)

匿名 (未验证) 提交于 2019-12-02 23:57:01

传送门

题意:
现在需要维护两种操作,一种是插入一条线段,另一种是询问\(x=k\)时,最上方线段的编号,如有多个线段处于最大值状态,那么就输出编号最小的。
强制在线。

思路:
这就是一个李超树的模板题...
李超树一般就可以用来维护一些跟线段、直线有关的问题,比如询问当\(x=x_0\)时,所有线段的最大值、最小值等等,也可以用来维护凸包什么的。
写法比普通线段树写起来稍微细节要多点,核心思想感觉还是标记永久化?每次如果在一段区间上面存在交点,那么就保留优势段更长的线段,然后下放另外一半;每次询问的时候跑到最下面答案就出来了。
细节详见代码吧,主要关于空间有个问题还不是很懂,这个题我开\(8\)倍空间才能过,讲道理\(4\)倍应该够了呀。。有点谜感觉。。。

#include <bits/stdc++.h> using namespace std; typedef long long ll; const int N = 1e5 + 5, MAX = 50005; int n;  struct node{     bool sign; int id;     double k, b;     void upd(int _id, double _k, double _b) {         id = _id, k = _k, b = _b;     } }tr[MAX << 3];  void update(int o, int l, int r, int id, double k, double b) {     if(!tr[o].sign) {         tr[o].sign = 1;         tr[o].upd(id, k, b);         return;     }     double l1 = l * tr[o].k + tr[o].b, l2 = l * k + b;     double r1 = r * tr[o].k + tr[o].b, r2 = r * k + b;     if(l2 <= l1 && r2 <= r1) return;     if(l2 > l1 && r2 > r1) {         tr[o].upd(id, k, b); return;     }     int mid = (l + r) >> 1;     double x = (tr[o].b - b) / (k - tr[o].k);     if(x <= mid) {         if(l1 > l2) update(o << 1, l, mid, tr[o].id, tr[o].k, tr[o].b), tr[o].upd(id, k, b);         else update(o << 1, l, mid, id, k, b);     } else {         if(l1 > l2) update(o << 1|1, mid + 1, r, id, k, b);         else update(o << 1|1, mid + 1, r, tr[o].id, tr[o].k, tr[o].b), tr[o].upd(id, k, b);     } }  void update(int o, int l, int r, int L, int R, int id, double k, double b) {     if(L <= l && r <= R) {         update(o, l, r, id, k, b); return;     }     int mid = (l + r) >> 1;     if(L <= mid) update(o << 1, l, mid, L, R, id, k, b);     if(R > mid) update(o << 1|1, mid + 1, r, L, R, id, k, b); }  void chk(int &res, int o1, int o2, int x) {     double y1, y2;     y1 = x * tr[o1].k + tr[o1].b;     y2 = x * tr[o2].k + tr[o2].b;     if(y1 > y2 && tr[o1].sign) res = o1;     else if(y1 < y2 && tr[o2].sign) res = o2;     else if(y1 == y2){         if(tr[o1].id < tr[o2].id && tr[o1].sign) res = o1;         else if(tr[o1].id > tr[o2].id && tr[o2].sign) res = o2;     }     return; }  int query(int o, int l, int r, int p) {     if(l == r) return o;     int mid = (l + r) >> 1, res = 0;     if(p <= mid) chk(res, query(o << 1, l, mid, p), o, p);     else chk(res, query(o << 1|1, mid + 1, r, p), o, p);     return res; }  int main() { //    freopen("input.in", "r", stdin);     scanf("%d", &n);     int lastans = 0, cnt = 0;     for(int i = 1; i <= n; i++) {         int op; scanf("%d", &op);         if(op == 0) {             int k; scanf("%d", &k);             int x = (k + lastans - 1) % 39989 + 1;             int o = query(1, 1, MAX, x);             lastans = tr[o].id;             printf("%d\n", lastans);         } else {             int x1, x2, y1, y2; ++cnt;             scanf("%d%d%d%d", &x1, &y1, &x2, &y2);             x1 = (x1 + lastans - 1) % 39989 + 1;             y1 = (y1 + lastans - 1) % 1000000000 + 1;             x2 = (x2 + lastans - 1) % 39989 + 1;             y2 = (y2 + lastans - 1) % 1000000000 + 1;             if(x1 > x2) swap(x1, x2), swap(y1, y2);             double k = 1.0 * (y1 - y2) / (x1 - x2), b = y1 - k * x1;             update(1, 1, MAX, x1, x2, cnt, k, b);         }     }     return 0; }
标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!