洛谷P4097 【模板】李超线段树 / [HEOI2013] Segment 题解 李超线段树 模板题

题目链接:https://www.luogu.com.cn/problem/P4097

解题思路:完全来自 oi.wiki

双倍经验:P4254 [JSOI2008] Blue Mary 开公司(更简单,因为每次更新都是整个区间)

示例程序:

#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e5 + 5, mod = 39989;
const double eps = 1e-9;

// x>y:返回1; x<y:返回-1; x=y:返回0
int cmp(double x, double y) {
    if (x - y > eps) return 1;
    if (y - x > eps) return -1;
    return 0;
}

struct Line {
    double k, b; // y=kx+b
} line[maxn];

int n, idx, lastans;

int trans(int x, int m = mod) {
    return (x + lastans - 1) % m + 1;
}

void new_line(int x0, int y0, int x1, int y1) {
    if (x0 == x1) {
        line[++idx] = {0, 1.0 * max(y0, y1)};
    }
    else {
        double k = 1.0 * (y1 - y0) / (x1 - x0);
        double b = y0 - k * x0;
        line[++idx] = {k, b};
    }
}

// 返回第 p 条线段在横坐标为 x 时对应的纵坐标 y
double get_y(int p, int x) {
    return line[p].k * x + line[p].b;
}

int tr[(mod+5)<<2];
#define lson l, mid, u<<1
#define rson mid+1, r, u<<1|1

void upd(int p, int l, int r, int u) {
    int &q = tr[u], mid = l + r >> 1;
    int c_mid = cmp(get_y(p, mid), get_y(q, mid));
    if (c_mid == 1 || !c_mid && p < q) swap(p, q);
    int c_l = cmp(get_y(p, l), get_y(q, l)), c_r = cmp(get_y(p, r), get_y(q, r));
    if (c_l == 1 || !c_l && p < q) upd(p, lson);
    if (c_r == 1 || !c_r && p < q) upd(p, rson);
}

void update(int p, int L, int R, int l, int r, int u) {
    if (L <= l && r <= R) {
        upd(p, l, r, u);
        return;
    }
    int mid = l + r >> 1;
    if (L <= mid) update(p, L, R, lson);
    if (R > mid) update(p, L, R, rson);
}

pair<int, double> query(int x, int l, int r, int u) {
    int p = tr[u];
    double ans = get_y(p, x);
    if (l == r)
        return {p, ans};
    int mid = l + r >> 1;
    auto [q, tmp] = (x <= mid) ? query(x, lson) : query(x, rson);
    int c_mid = cmp(tmp, ans);
    if (c_mid == 1 || !c_mid && q < p) {
        p = q;
        ans = tmp;
    }
    return { p, ans };
}

int main() {
    scanf("%d", &n);
    while (n--) {
        int op;
        scanf("%d", &op);
        if (op == 0) {
            long long x, k;
            scanf("%lld", &k);
            x = trans(k);
            lastans = query(x, 1, mod, 1).first;
            printf("%d\n", lastans);
        }
        else { // op == 1
            long long x0, y0, x1, y1;
            scanf("%lld%lld%lld%lld", &x0, &y0, &x1, &y1);
            x0 = trans(x0);
            y0 = trans(y0, 1e9);
            x1 = trans(x1);
            y1 = trans(y1, 1e9);
            if (x0 > x1) {
                swap(x0, x1);
                swap(y0, y1);
            }
            new_line(x0, y0, x1, y1);
            update(idx, x0, x1, 1, mod, 1);
        }
    }
    return 0;
}
posted @ 2026-03-18 22:38  quanjun  阅读(2)  评论(0)    收藏  举报