博客
关于我
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请求html_使用Python请求获取HTML?
    查看>>
    Python 之匿名函数和偏函数
    查看>>
    python 之栈的实现
    查看>>
    python语音播放
    查看>>
    python语言:装饰器原理
    查看>>
    Python 交互式数据可视化详解
    查看>>
    python语言有哪些优点和缺点_Python有哪些优缺点,你了解吗?
    查看>>
    Python 从入门到精通:30天速成教程到底有多狠?你能坚持下来吗?
    查看>>
    Python 从数据库中存储和检索密码的最安全方法
    查看>>
    Python语言及其应用 - 知识点遍历
    查看>>
    Python 优化提速的 8 个小技巧
    查看>>
    Python 余弦相似度与皮尔逊相关系数 计算
    查看>>
    python 使用execjs 报编码错误解决办法,UnicodeDecodeError: ‘gbk‘ codec can‘t decode byte 0xac in position 145: il
    查看>>
    python 使用filetype校验文件
    查看>>
    Python 使用flush函数将缓冲区数据立即写磁盘
    查看>>
    python 使用in判断不准确,in不好使
    查看>>
    Python 使用pandas 进行查询和统计详解
    查看>>
    Redis 配置文件redis.conf详细解释
    查看>>
    python网络爬虫(2)——scrapy框架的基础使用
    查看>>
    python网络爬虫实例教程试读_Python网络爬虫实战教程(全套完整版) - 学途无忧网 - 做技术的王者 - Powered By EduSoho...
    查看>>