A了,但不理解

P4097 【模板】李超线段树 / [HEOI2013] Segment

ln001 @ 2024-08-11 17:49:27

AC代码:

// Problem: P4097 【模板】李超线段树 / [HEOI2013] Segment
// Contest: Luogu
// URL: https://www.luogu.com.cn/problem/P4097
// Time Limit: 1000 ms
// Start Time:2024-08-11 09:52:44
//
// Powered by CP Editor (https://cpeditor.org)

#include <bits/stdc++.h>
#ifndef LOCAL
#define csf std::cerr.setstate(std::ios_base::failbit)
#define db(x)
#else
#define db(x) cerr << __FUNCTION__ << " L" << __LINE__ << " " << #x " = " << (x) << endl
#define csf
#endif
using ll = long long;
#define double long double //add
#define f(x, y, z) for (ll x = (y); x <= (z); x++)
inline ll read();
using namespace std;

const long long INF = 0x3f3f3f3f3f3f3f3f, N = 1e5 + 10, M = 4e4 + 10, Py = 1e9;

pair<double, double /*change -> ll to double*/> getf(ll xa, ll ya, ll xb, ll yb)
{
    if (xa == xb)
        return make_pair(0, max(ya, yb));
    double k = (ya - yb);
    k /= (xa - xb);
    double b = ya - k * xa; // change
    return make_pair(k, b);
}
struct edge
{
    ll lx = INF, rx = -INF;
    double k, b = -INF; //change
    void init(ll xa, ll ya, ll xb, ll yb)
    {
        auto res = getf(xa, ya, xb, yb);
        k = res.first;
        b = res.second;
        lx = min(xa, xb);
        rx = max(xa, xb);
    }
} e[N]; //线段
ll cnt = 0;

double get_y(ll x, ll id)
{
    return e[id].k * x + e[id].b;
}
ll get_max(ll x, ll id1, ll id2)
{
    double ya = get_y(x, id1); //change -> ll to double
    double yb = get_y(x, id2);
    if (ya == yb)
        return min(id1, id2);
    if (ya > yb)
        return id1;
    return id2;
}
bool has_intrsion(ll lx, ll rx, ll id1, ll id2)
{ //判断是否有交点
    if (id1 == 0 || id2 == 0)
        return 1;
    if (get_y(lx, id1) == get_y(lx, id2))
        return 1; //add
    if (get_y(lx, id1) < get_y(lx, id2))
        swap(id1, id2);
    if (get_y(rx, id1) <= get_y(rx, id2))
        return 1;
    return 0;
}
bool intrsion_pos(ll lx, ll rx, ll id1, ll id2)
{ //如果交点在左侧返回0,在右侧返回1。在中间时返回0
    ll mid = (lx + rx) / 2;
    return has_intrsion(mid, rx, id1, id2); //change?
}

ll stick[M]; //竖直线段

ll n;
namespace lc_tree
{
#define ls(s) (s << 1)
#define rs(s) (s << 1 | 1)
struct node
{
    ll l = INF, r = -INF; //区间范围
    ll e;                 //线段标号(del -> 赋初值(默认为0))
} t[4 * M];
void build(ll p = 1, ll l = 1, ll r = 39989)
{
    t[p].l = l;
    t[p].r = r;
    if (l == r)
        return;
    ll mid = (l + r) >> 1;
    build(ls(p), l, mid);
    build(rs(p), mid + 1, r);
}
void sent(ll id, ll p = 1)
{
    if (e[id].lx > t[p].r || e[id].rx < t[p].l)
        return;
    else if (e[id].lx > t[p].l || e[id].rx < t[p].r)
    {
        if (t[p].l != t[p].r)
        {
            sent(id, ls(p));
            sent(id, rs(p));
        }
        return;
    }

    ll oldd = t[p].e, neww = id, mid = (t[p].l + t[p].r) / 2;
    if (get_max(mid, t[p].e, id) == id)
    { //替换当前区间
        t[p].e = id;
        swap(oldd, neww);
    }
    if (t[p].l != t[p].r && has_intrsion(t[p].l, t[p].r, oldd, neww))
    {
        if (get_y(mid, oldd) == get_y(mid, neww))          //add
        {                                                  //如果交点在中间
            if (get_y(t[p].l, oldd) < get_y(t[p].l, neww)) //左侧更优
                sent(neww, ls(p));
            else
                sent(neww, rs(p));
        }
        else
        {
            if (!intrsion_pos(t[p].l, t[p].r, oldd, neww)) //add
                sent(neww, ls(p));
            else
                sent(neww, rs(p));
        }
    }
    return;
}
ll check(ll x, ll p = 1)
{
    ll res = 0;
    if (t[p].l > x || t[p].r < x)
        return 0;
    res = get_max(x, res, t[p].e);
    if (t[p].l != t[p].r)
    {
        res = get_max(x, res, check(x, ls(p)));
        res = get_max(x, res, check(x, rs(p)));
    }
    return res;
}
#undef ls
#undef rs
} // namespace lc_tree

signed main()
{
    csf;
    cin >> n;
    lc_tree::build();
    ll lastans = 0;

    f(i, 1, n)
    {
        ll op;
        cin >> op;
        if (op == 0)
        {
            ll k;
            cin >> k;
            ll ques = (k + lastans - 1) % 39989 + 1;
            lastans = get_max(ques, stick[ques], lc_tree::check(ques)); //默认为0
            cout << lastans << endl;
        }
        else
        {
            ll xa, ya, xb, yb;
            cin >> xa >> ya >> xb >> yb;
            xa = (xa + lastans - 1) % 39989 + 1;
            xb = (xb + lastans - 1) % 39989 + 1;
            ya = (ya + lastans - 1) % Py + 1;
            yb = (yb + lastans - 1) % Py + 1;

            e[++cnt].init(xa, ya, xb, yb);
            if (xa == xb)
            {
                stick[xa] = get_max(xa, stick[xa], cnt);
            }
            else
            {
                lc_tree::sent(cnt);
            }
        }
    }
    return 0;
}

但是把intrsion_pos函数第二行的return has_intrsion(mid, rx, id1, id2);改成return has_intrsion(mid + 1, rx, id1, id2);就WA了。


by ln001 @ 2024-08-11 17:52:34

重新补一个好看一点的AC代码

// Problem: P4097 【模板】李超线段树 / [HEOI2013] Segment
// Contest: Luogu
// URL: https://www.luogu.com.cn/problem/P4097
// Time Limit: 1000 ms
// Start Time:2024-08-11 09:52:44
//
// Powered by CP Editor (https://cpeditor.org)

#include <bits/stdc++.h>
#ifndef LOCAL
#define csf std::cerr.setstate(std::ios_base::failbit)
#define db(x)
#else
#define db(x) cerr << __FUNCTION__ << " L" << __LINE__ << " " << #x " = " << (x) << endl
#define csf
#endif
using ll = long long;
#define double long double //add
#define f(x, y, z) for (ll x = (y); x <= (z); x++)
inline ll read();
using namespace std;

const long long INF = 0x3f3f3f3f3f3f3f3f, N = 1e5 + 10, M = 4e4 + 10, Py = 1e9;

pair<double, double> getf(ll xa, ll ya, ll xb, ll yb) //由两点式转换为一般式
{
    if (xa == xb)
        return make_pair(0, max(ya, yb));
    double k = (ya - yb);
    k /= (xa - xb);
    double b = ya - k * xa; 
    return make_pair(k, b);
}
struct edge
{
    ll lx = INF, rx = -INF;
    double k, b = -INF; 
    void init(ll xa, ll ya, ll xb, ll yb)
    {
        auto res = getf(xa, ya, xb, yb);
        k = res.first;
        b = res.second;
        lx = min(xa, xb);
        rx = max(xa, xb);
    }
} e[N]; //线段
ll cnt = 0;

double get_y(ll x, ll id)
{
    return e[id].k * x + e[id].b;
}
ll get_max(ll x, ll id1, ll id2)
{
    double ya = get_y(x, id1);
    double yb = get_y(x, id2);
    if (ya == yb)
        return min(id1, id2);
    if (ya > yb)
        return id1;
    return id2;
}
bool has_intrsion(ll lx, ll rx, ll id1, ll id2)
{ //判断是否有交点
    if (id1 == 0 || id2 == 0)
        return 1;
    if (get_y(lx, id1) == get_y(lx, id2))
        return 1;
    if (get_y(lx, id1) < get_y(lx, id2))
        swap(id1, id2);
    if (get_y(rx, id1) <= get_y(rx, id2))
        return 1;
    return 0;
}
bool intrsion_pos(ll lx, ll rx, ll id1, ll id2)
{ //如果交点在左侧返回0,在右侧返回1。在中间时返回0
    ll mid = (lx + rx) / 2;
    return has_intrsion(mid, rx, id1, id2); 
}

ll stick[M]; //竖直线段

ll n;
namespace lc_tree
{
#define ls(s) (s << 1)
#define rs(s) (s << 1 | 1)
struct node
{
    ll l = INF, r = -INF; //区间范围
    ll e;                 //线段标号(del -> 赋初值(默认为0))
} t[4 * M];
void build(ll p = 1, ll l = 1, ll r = 39989)
{
    t[p].l = l;
    t[p].r = r;
    if (l == r)
        return;
    ll mid = (l + r) >> 1;
    build(ls(p), l, mid);
    build(rs(p), mid + 1, r);
}
void sent(ll id, ll p = 1)
{
    if (e[id].lx > t[p].r || e[id].rx < t[p].l)
        return;
    else if (e[id].lx > t[p].l || e[id].rx < t[p].r)
    {
        if (t[p].l != t[p].r)
        {
            sent(id, ls(p));
            sent(id, rs(p));
        }
        return;
    }

    ll oldd = t[p].e, neww = id, mid = (t[p].l + t[p].r) / 2;
    if (get_max(mid, t[p].e, id) == id)
    { //替换当前区间
        t[p].e = id;
        swap(oldd, neww);
    }
    if (t[p].l != t[p].r && has_intrsion(t[p].l, t[p].r, oldd, neww))
    {
        if (get_y(mid, oldd) == get_y(mid, neww))          //add
        {                                                  //如果交点在中间
            if (get_y(t[p].l, oldd) < get_y(t[p].l, neww)) //左侧更优
                sent(neww, ls(p));
            else
                sent(neww, rs(p));
        }
        else
        {
            if (!intrsion_pos(t[p].l, t[p].r, oldd, neww))
                sent(neww, ls(p));
            else
                sent(neww, rs(p));
        }
    }
    return;
}
ll check(ll x, ll p = 1)
{
    ll res = 0;
    if (t[p].l > x || t[p].r < x)
        return 0;
    res = get_max(x, res, t[p].e);
    if (t[p].l != t[p].r)
    {
        res = get_max(x, res, check(x, ls(p)));
        res = get_max(x, res, check(x, rs(p)));
    }
    return res;
}
#undef ls
#undef rs
} // namespace lc_tree

signed main()
{
    csf;
    cin >> n;
    lc_tree::build();
    ll lastans = 0;

    f(i, 1, n)
    {
        ll op;
        cin >> op;
        if (op == 0)
        {
            ll k;
            cin >> k;
            ll ques = (k + lastans - 1) % 39989 + 1;
            lastans = get_max(ques, stick[ques], lc_tree::check(ques));
            cout << lastans << endl;
        }
        else
        {
            ll xa, ya, xb, yb;
            cin >> xa >> ya >> xb >> yb;
            xa = (xa + lastans - 1) % 39989 + 1;
            xb = (xb + lastans - 1) % 39989 + 1;
            ya = (ya + lastans - 1) % Py + 1;
            yb = (yb + lastans - 1) % Py + 1;

            e[++cnt].init(xa, ya, xb, yb);
            if (xa == xb)
            {
                stick[xa] = get_max(xa, stick[xa], cnt);
            }
            else
            {
                lc_tree::sent(cnt);
            }
        }
    }
    return 0;
}

|