zoukankan      html  css  js  c++  java
  • P4097 [HEOI2013]Segment(李超树)

    传送门

    题意:
    现在需要维护两种操作,一种是插入一条线段,另一种是询问(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
    ", 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;
    }
    
    
  • 相关阅读:
    skynet源代码学习
    白话经典算法系列之七 堆与堆排序
    数据结构与算法二
    [hadoop系列]Pig的安装和简单演示样例
    感动前行——给医学媳妇写的演讲稿(非IT类)
    怎样提高团队管理能力3
    Linux守护进程的编程实现
    人脸识别 开放书籍 下载地址
    Objective-C中经常使用的结构体NSRange,NSPoint,NSSize(CGSize),NSRect
    动态规划整理(两)
  • 原文地址:https://www.cnblogs.com/heyuhhh/p/11449401.html
Copyright © 2011-2022 走看看