• P4097 [HEOI2013]Segment(李超线段树模板)


    P4097 HEOI2013 Segment
    今天我们来学习李超线段树。
    他就是一个维护线段的线段树。
    学习完毕
    李超线段树是线段树的一个变种,支持在平面直角坐标系中动态插入线段,查询一条竖线与所有线段的交点纵坐标的最大值或最小值。
    区间记录 (mid) 点在上面的线段。(也就是区间最优秀线段)
    caution: 大区间最优不一定是小区间最优)
    举个例子:
    pic.png
    显然 (S_1)(L, R) 区间最优,但是不是 (L, mid) 区间最优。
    (S_2) 不是 (L, R) 区间最优,但是是 (L, mid) 区间最优。
    所以我们在一个区间有最优线段的时候,更新用的是交换而不是直接替代,然后再考虑原线段的当前线段的交点位置,然后在交点位置的那个区间再讨论。(没有的时候直接替代就行了)

    (insert)代码:

    void ins(ll node, ll l, ll r, line seg) {
        if (l <= t[node].l && t[node].r <= r) {
            dd lp = t[node].L.calcy(t[node].l), rp = t[node].L.calcy(t[node].r);
            dd lq = seg.calcy(t[node].l), rq = seg.calcy(t[node].r);
            if (!t[node].flag) t[node].flag = 1, t[node].L = seg;
            else if (lq - lp > ep && rq - rp > ep) t[node].L = seg;
            else if (lq - lp > ep || rq - rp > ep) {
                ll mid = (t[node].l + t[node].r) >> 1;
                if (seg.calcy(mid) - t[node].L.calcy(mid) > ep) swap(t[node].L, seg); // 这里可以保证找交点所在的区间进行再讨论一定是对的,同时更新区间最优线段。
                if (mid - met(seg, t[node].L) > ep) ins(node << 1, l, r, seg);
                else ins(node << 1 | 1, l, r, seg);
            }
            return;
        }
        ll mid = (t[node].l + t[node].r) >> 1;
        if (l <= mid) ins(node << 1, l, r, seg);
        if (mid < r) ins(node << 1 | 1, l, r, seg);
        return;
    }
    

    下面是全部代码:

    #include <algorithm>
    #include <iostream>
    #include <cstring>
    #include <cstdio>
    
    using namespace std;
    
    typedef double dd;
    typedef long long ll;
    typedef pair<double, ll> pdl;
    const ll MAXN = 1e5+10;
    const dd ep = 1e-6;
    
    struct line {
        dd k, b;
        ll id;
        line(dd k=0, dd b=0, ll id=0):k(k),b(b),id(id){}
        dd calcy(ll pos) {
            return k * pos + b;
        }
    };
    
    struct nod {
        ll l, r;
        line L;
        bool flag;
    	nod(ll l,ll r,line L,bool flag):l(l),r(r),L(L),flag(flag){}
    	nod(){}
    } t[MAXN << 2];
    
    ll N, M, lstans = 0, B = 39989, cnt;
    
    pdl ask(ll, ll);
    void build(ll, ll, ll);
    void ins(ll, ll, ll, line);
    dd met(line, line);
    
    int main() {
    	#ifdef ZZCAKIOI
        freopen("P4097_1.in", "r", stdin);
        //freopen("P4097.out", "w", stdout);
    	#endif
        ios::sync_with_stdio(false);
        cin >> N;
        build(1, 0, B);
        for (ll i = 1, op; i <= N; i++) {
            cin >> op;
            if (op == 1) {
                ll x1, x2, y1, y2;
                cin >> x1 >> y1 >> x2 >> y2;
                x1 = (x1 + lstans - 1) % B + 1;
                x2 = (x2 + lstans - 1) % B + 1;
                y1 = (y1 + lstans - 1) % 1000000000 + 1;
                y2 = (y2 + lstans - 1) % 1000000000 + 1;
                if (x1 > x2) {
                    swap(x1, x2);
                    swap(y1, y2);
                }
                cnt++;
                if (x1 != x2) {
                    dd kk = (y2 - y1 + 0.0) / (x2 - x1 + 0.0);
                    ins(1, x1, x2, {kk, (dd)y1 - (dd)x1 * kk, cnt});
                } else ins(1, x1, x2, {0, (dd)max(y1, y2), cnt});
            } else {
                ll k, x;
                cin >> k;
                x = (k + lstans - 1) % B + 1;
            	lstans = ask(1, x).second;
            	cout << lstans << '
    ';
            }
        }
        return 0;
    }
    
    void build(ll node, ll l, ll r) {
        t[node] = {l, r, line(), false};
        if (l == r) return;
        ll mid = (l + r) >> 1;
        build(node << 1, l, mid);
        build(node << 1 | 1, mid+1, r);
    }
    
    void ins(ll node, ll l, ll r, line seg) {
        if (l <= t[node].l && t[node].r <= r) {
            dd lp = t[node].L.calcy(t[node].l), rp = t[node].L.calcy(t[node].r);
            dd lq = seg.calcy(t[node].l), rq = seg.calcy(t[node].r);
            if (!t[node].flag) t[node].flag = 1, t[node].L = seg;
            else if (lq - lp > ep && rq - rp > ep) t[node].L = seg;
            else if (lq - lp > ep || rq - rp > ep) {
                ll mid = (t[node].l + t[node].r) >> 1;
                if (seg.calcy(mid) - t[node].L.calcy(mid) > ep) swap(t[node].L, seg);
                if (mid - met(seg, t[node].L) > ep) ins(node << 1, l, r, seg);
                else ins(node << 1 | 1, l, r, seg);
            }
            return;
        }
        ll mid = (t[node].l + t[node].r) >> 1;
        if (l <= mid) ins(node << 1, l, r, seg);
        if (mid < r) ins(node << 1 | 1, l, r, seg);
        return;
    }
    
    pdl ask(ll node, ll pos) {
        double an = t[node].L.calcy(pos);
        ll id = t[node].L.id;
        if (t[node].l == t[node].r) return make_pair(an, id);
        ll mid = (t[node].l + t[node].r) >> 1;
        if (pos <= mid) {
            pdl tem = ask(node << 1, pos);
            if (tem.first > an || (abs(tem.first - an) < ep && tem.second < id)) an = tem.first, id = tem.second;
        } else {
            pdl tem = ask(node << 1 | 1, pos);
            if (tem.first > an || (abs(tem.first - an) < ep && tem.second < id)) an = tem.first, id = tem.second; 
        }
        return make_pair(an, id);
    }
    
    dd met(line a, line b) {
        return (a.b - b.b) / (b.k - a.k);
    }
    
  • 相关阅读:
    C# 抽象方法和虚方法的区别
    xmlhttprequest readyState 属性的五种状态
    ServiceStack破解文件
    k8s部署mysql
    docker 开放2376端口的问题
    .net core 发布到IIS 没有 web.config 文件
    1064
    docker mysql 主从同步配置
    Docker 鼠标在虚拟机与主机之间自由切换
    Socket原理解析2
  • 原文地址:https://www.cnblogs.com/Gensokyo-Alice/p/13725088.html
Copyright © 2020-2023  润新知