博客
关于我
E - 买礼物(链表+线段树)
阅读量:323 次
发布时间:2019-03-04

本文共 3284 字,大约阅读时间需要 10 分钟。

对于这个问题,我们可以使用一个双向链表结构来记录每个数的左右邻居,并结合并查集来维护这些邻居关系。具体来说,我们使用两个数组 L 和 R,分别记录每个数的最左边和最右边相邻的数。这样,当删除一个数时,只需要更新它左右邻居的指针即可。

解题思路

  • 初始化邻居关系:

    • 使用两个数组 L 和 R,其中 L[i] 记录数 a[i] 的最左边相邻数的位置,R[i] 记录最右边相邻数的位置。
    • 初始化 pre 数组来维护每个数的最近访问位置。
  • 删除操作:

    • 当删除一个数 a[l] 时,需要更新 L[l] 和 R[l] 的邻居关系。
    • 特别地,链表的首尾节点需要特殊处理,当删除首尾节点时,可能会影响其邻居关系。
  • 查询操作:

    • 使用树状数组(Fenwick Tree)来维护区间内的最大值。
    • 对于查询操作,查询区间 [l, r] 内是否存在两个相同的数,可以通过查找区间内的最大值 cur_max 来判断。
    • 如果 cur_max 在区间 [l, r] 内,则说明存在重复的数,输出 1;否则,输出 0。
  • 代码实现细节

    #include 
    #include
    using namespace std;#define ENDL "\n"typedef long long ll;const int inf = 0x3f3f3f3f;const int maxn = 5e5 + 10;const int Mod = 1e9 + 7;int n;int a[maxn], L[maxn], R[maxn], pre[maxn * 2];int tree[maxn << 2], size = 1;void build(int i, int l, int r) { if (l == r) { tree[i] = R[l]; return; } int mid = (l + r) >> 1; int k = i << 1; build(k, l, mid); build(k | 1, mid + 1, r); tree[i] = min(tree[k], tree[k | 1]);}void change(int i, int l, int r, int pos, int x) { if (l == r) { tree[i] = x; return; } int mid = (l + r) >> 1; int k = i << 1; if (pos <= mid) { change(k, l, mid, pos, x); } else { change(k | 1, mid + 1, r, pos, x); } tree[i] = min(tree[k], tree[k | 1]);}int query(int i, int l, int r, int x, int y) { if (l == x && r == y) { return tree[i]; } int res = inf; int mid = (l + r) >> 1; int k = i << 1; if (y <= mid) { res = query(k, l, mid, x, y); } else if (x > mid) { res = query(k | 1, mid + 1, r, x, y); } else { int left = query(k, l, mid, x, mid); int right = query(k | 1, mid + 1, r, mid + 1, y); res = min(left, right); } return res;}int main() { ios::sync_with_stdio(0); cin.tie(0); cout.tie(0); int q; cin >> n >> q; memset(pre, inf, sizeof pre); for (int i = 1; i <= n; ++i) { cin >> a[i]; if (pre[a[i]] != inf) { L[i] = pre[a[i]]; } else { L[i] = inf; } pre[a[i]] = i; } pre memset to inf; for (int i = n; i >= 1; --i) { if (pre[a[i]] != inf) { R[i] = pre[a[i]]; } else { R[i] = inf; } pre[a[i]] = i; } build(1, 1, n); while (q--) { int op; cin >> op; if (op == 1) { int l; cin >> l; if (L[l] != inf) { if (R[l] != inf) { int old = R[l]; L[old] = inf; R[l] = inf; } if (L[l] != inf) { R[L[l]] = l; } if (R[l] != inf) { L[R[l]] = l; } } L[l] = R[l] = inf; change(1, 1, n, l, inf); } else { int l, r; cin >> l >> r; if (l > r) { l = r; } int cur = query(1, 1, n, l, r); if (cur != inf && l <= cur && cur <= r) { cout << "1" << ENDL; } else { cout << "0" << ENDL; } } } return 0;}

    代码解释

    • 初始化:使用 L 和 R 数组记录每个数的左右邻居,pre 数组维护每个数的最近访问位置。
    • 删除操作:更新数的左右邻居关系,并使用树状数组维护区间内的最大值。
    • 查询操作:通过树状数组查找区间内的最大值,判断其是否在区间内,确定是否存在重复数。

    这种方法高效地处理了大规模数据的操作,确保了在合理时间内完成查询和删除任务。

    转载地址:http://ppqq.baihongyu.com/

    你可能感兴趣的文章
    python初步学习-python数据类型-集合(set)
    查看>>
    python列表生成字典_Python中将字典转换为列表的方法
    查看>>
    python列表对应元素合并为列表及判断一个列表是几维
    查看>>
    python列表去重复后按照顺序_从包含不可共元素的Python列表中删除重复元素,同时保留顺序?...
    查看>>
    python列表前几个_python之列表
    查看>>
    python列表元组
    查看>>
    Python列表/元组/字典和集合使用
    查看>>
    python列表 行列选择_python_pandas_dataframe_行列选择_切片操作
    查看>>
    python列表
    查看>>
    python列出当前目录、子目录和文件的脚本
    查看>>
    python+flask计算机毕业设计骨科门诊患者档案管理系统(程序+开题+论文)
    查看>>
    python+flask计算机毕业设计高校体测管理系统的设计与实现(程序+开题+论文)
    查看>>
    Python切片对象和__getitem__
    查看>>
    python+flask计算机毕业设计高校体育竞赛成绩管理系统的设计与实现(程序+开题+论文)
    查看>>
    python+flask计算机毕业设计高校体育赛事系统(程序+开题+论文)
    查看>>
    python+flask计算机毕业设计高校体育运动会比赛系统(程序+开题+论文)
    查看>>
    python+flask计算机毕业设计高校危化品管理系统(程序+开题+论文)
    查看>>
    python+flask计算机毕业设计高校团委事务管理系统(程序+开题+论文)
    查看>>
    Python切片(%s)
    查看>>
    python+flask计算机毕业设计高校学生选课系统(程序+开题+论文)
    查看>>