ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

「JOISC 2019 Day3」穿越时空 Bitaro

2022-01-23 17:02:21  阅读:224  来源: 互联网

标签:res 合并 Day3 else JOISC 2019 区间 三元组 define


「JOISC 2019 Day3」穿越时空 Bitaro

数据结构,线段树

考虑每次行动

显然暴力贪心走是正确的

但时间的流逝很麻烦

可以将每对 \([L_i, R_i] \longrightarrow [L_i - i, R_i - i]\)

这样就可以抵消掉时间流动的问题,就像这样

对于当前时间 \(t\) ,当前这条路时间 \([L_i, R_i]\)

  • \(t \in [L_i, R_i]\) ,直接走
  • \(t < L_i\) 等到 \(L_i\) 走
  • \(t > R_i\) 操作一下把时间调至 \(R_i\) 再走

现在每次操作是 \(O(n)\),总\(O(nq)\) ,可以获得 \(\color{lightgreen}4\) 分的好成绩

接下来考虑多次询问和修改

我们可以用一个三元组 \((a, b, c)\) 来表示一次行动,其中 \(a\) 表示开始时刻,\(b\) 表示结束时刻,\(c\) 表示倒流时间数

显然,对于每次询问,我们只需求出对应三元组的 \(c\) 即可

试着将一个三元组拆成两个有序的更小的三元组,这样我们可以将询问的三元组一直拆下去,直到可知为止

反过来考虑将两个三元组 \((a_1, b_1, c_1)\) 和 \((a_2, b_2, c_2)\) 按序合并为一个三元组

如图,前后两次行动可以接上中间的差值,合并为一次行动

\((a_1, b_1, c_1) + (a_2, b_2, c_2) \longrightarrow (a_1, b_2, c_1 + c_2 + \Delta c)\)

但是题目给的是一个二元区间 \([L_i, R_i]\) ,考虑合并两个二元区间会变成什么

当两个区间有交集时,合并和便是个更小的区间,也就是指只有在这个更小的区间才能通过这两个区间,比如

图中转化为:

\([L_1, R_1] + [L_2, R_2] \longrightarrow [\max(L_1, L_2), \min(R_1, R_2)]\)

当两个区间无交集时,遍合并为了三元组,表示通过这两个区间需要代价(等待或者时间倒流),比如

图中转化为:

\([L_1, R_1] + [L_2, R_2] \longrightarrow (L_1, R_2, L_1 - R_2)\)

现在考虑二元与三元合并

红色的是合并后的三元组

以及三元与二元合并

合并,修改,查询,想到用线段树维护

所以每次查询 \(A, B, C, D\),只需将范围内的所有区间合并起来就行了,但由于起点终点有时间限制,所有在构造两个区间与之并起来,就能得到此次行动的三元组

\([B - A, B - A] + \text{query}(A, C- 1) + [D - C, D - C]\)

减 \(A\) 减 \(C\) 是减去位置,抵消流动时间

特别注意的地方,就是询问中会有反向的,也就是从后边的城市到前面的城市

对于这些询问,只需将其提出来,反向建线段树再做就行了

可以获得 \(\color{red}{100}\) 分的好成绩

#include <bits/stdc++.h>
#define re register
// #define int long long
// #define pair pair<int, int>
#define File(a) freopen(a".in", "r", stdin), freopen(a".out", "w", stdout);
#define getchar() (p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, 1 << 21, stdin), p1 == p2) ? EOF : *p1++)
char buf[1 << 21], *p1 = buf, *p2 = buf;
using namespace std;
inline int read()
{
    re int x = 0, f = 0;
    re char ch = getchar();
    while (!isdigit(ch)) {if (ch == '-') f = 1; ch = getchar();}
    while (isdigit(ch)) {x = (x << 3) + (x << 1) + ch - 48; ch = getchar();}
    return f ? -x : x;
}
inline string getstr()
{
    string res = "";
    re char ch = getchar();
    while (isspace(ch)) ch = getchar();
    while (!isspace(ch)) res.push_back(ch), ch = getchar();
    return res;
}
const int N = 3e5 + 5, P = 1e9 + 9;
int n;
struct node
{
    long long a, b, c;
    inline node operator + (const node &x) const
    {
        node res;
        if (a == 0 && b == 0 && c == 0) return x;
        if (x.a == 0 && x.b == 0 && x.c == 0) return *this;
        if (c == -1 && x.c == -1)
        {
            if (a > x.b) res = {a, x.b, a - x.b};
            else if (b < x.a) res = {b, x.a, 0};
            else res = {max(a, x.a), min(b, x.b), -1};
        }
        else if (c == -1)
        {
            if (b < x.a) res = {b, x.b, x.c};
            else if (a > x.a) res = {a, x.b, x.c + a - x.a};
            else res = x;
        }
        else if (x.c == -1)
        {
            if (b < x.a) res = {a, x.a, c};
            else if (b > x.b) res = {a, x.b, c + b - x.b};
            else res = *this;
        }
        else res = {a, x.b, max(b - x.a, 0ll) + c + x.c};
        return res;
    }
};
node tr[N << 2], A[N];
inline void built(int p, int l, int r)
{
    if (l > r) return;
    if (l == r) return void(tr[p] = {A[l].a - l, A[l].b - l - 1, -1});
    int mid = l + r >> 1;
    built(p << 1, l, mid);
    built(p << 1 | 1, mid + 1, r);
    tr[p] = tr[p << 1] + tr[p << 1 | 1];
}
inline void update(int p, int l, int r, int LR, node val)
{
    if (l == r) return void(tr[p] = val);
    int mid = l + r >> 1;
    if (LR <= mid) update(p << 1, l, mid, LR, val);
    else update(p << 1 | 1, mid + 1, r, LR, val);
    tr[p] = tr[p << 1] + tr[p << 1 | 1];
}
inline node ask(int p, int l, int r, int L, int R)
{
    if (L <= l && r <= R) return tr[p];
    int mid = l + r >> 1;
    node res = {0, 0, 0};
    if (L <= mid) res = res + ask(p << 1, l, mid, L, R);
    if (mid < R) res = res + ask(p << 1 | 1, mid + 1, r, L, R);
    return res;
}
long long ans[N];
struct
{
    int op, A, C, B, D;
}q[N];
signed main()
{
    bool flag = 1;
    n = read(); int T = read();
    for (re int i = 1; i < n; ++i) A[i] = {read(), read(), -1};
    built(1, 1, n - 1);
    for (re int i = 1; i <= T; ++i)
    {
        ans[i] = -1;
        q[i].op = read(), q[i].A = read(), q[i].B = read(), q[i].C = read();
        if (q[i].op == 1) update(1, 1, n - 1, q[i].A, {q[i].B - q[i].A, q[i].C - q[i].A - 1, -1});
        else
        {
            q[i].D = read();
            if (q[i].A == q[i].C) {ans[i] = max(0, q[i].B - q[i].D); continue;}
            if (q[i].A > q[i].C) {flag = 1; continue;}
            node res = ask(1, 1, n - 1, q[i].A, q[i].C - 1);
            res = node{q[i].B - q[i].A, q[i].B - q[i].A, -1} + res;
            res = res + node{q[i].D - q[i].C, q[i].D - q[i].C, -1};
            ans[i] = res.c;
        }
    }
    if (flag)
    {
        reverse(A + 1, A + n);
        built(1, 1, n - 1);
        for (re int i = 1; i <= T; ++i)
        {
            if (q[i].op != 1) q[i].C = n - q[i].C + 1, q[i].A = n - q[i].A + 1;
            else q[i].A = n - q[i].A;
        }
        for (re int i = 1; i <= T; ++i)
        {
            if (ans[i] != -1) continue;
            if (q[i].op == 1) update(1, 1, n - 1, q[i].A, {q[i].B - q[i].A, q[i].C - q[i].A - 1, -1});
            else
            {
                node res = ask(1, 1, n - 1, q[i].A, q[i].C - 1);
                res = node{q[i].B - q[i].A, q[i].B - q[i].A, -1} + res;
                res = res + node{q[i].D - q[i].C, q[i].D - q[i].C, -1};
                ans[i] = res.c;
            }
        }	
    }
    for (re int i = 1; i <= T; ++i) if (q[i].op != 1) printf("%lld\n", ans[i]);
    return 0;
}

标签:res,合并,Day3,else,JOISC,2019,区间,三元组,define
来源: https://www.cnblogs.com/After-glow/p/15836763.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有