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

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

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

解题思路

  • 初始化邻居关系

    • 使用两个数组 LR,其中 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;}

    代码解释

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

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

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

    你可能感兴趣的文章
    oracle 逻辑优化,提升高度,综合SQL上下文进行逻辑优化
    查看>>
    oracle 闪回关闭,关闭闪回即disable flashback的操作步骤
    查看>>
    oracle 限制用户并行,insert /*parallel */ 到不同用户,并行起不来的问题
    查看>>
    oracle--用户,权限,角色的管理
    查看>>
    Oracle-定时任务-JOB
    查看>>
    oracle.dataaccess 连接池,asp.net使用Oracle.DataAccess.dll连接Oracle
    查看>>
    oracle00205报错,Oracle控制文件损坏报错场景
    查看>>
    Oracle10g EM乱码之快速解决
    查看>>
    Oracle10g下载地址--多平台下的32位和64位
    查看>>
    Oracle10g安装了11g的ODAC后,PL/SQL连接提示TNS:无法解析指定的连接标识符
    查看>>
    oracle11g dataguard物理备库搭建(关闭主库cp数据文件到备库)
    查看>>
    Oracle11G基本操作
    查看>>
    Oracle11g服务详细介绍及哪些服务是必须开启的?
    查看>>
    Oracle11g静默安装dbca,netca报错处理--直接跟换操作系统
    查看>>
    oracle12安装软件后安装数据库,然后需要自己配置监听
    查看>>
    Oracle——08PL/SQL简介,基本程序结构和语句
    查看>>
    Oracle——distinct的用法
    查看>>
    Oracle、MySQL、SQL Server架构大对比
    查看>>
    oracle下的OVER(PARTITION BY)函数介绍
    查看>>
    Oracle中DATE数据相减问题
    查看>>