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

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


题目大意

给出一个序列,有以下两种操作:

  • 1    x 1~~x 1  x:将位置 x x x上的数删除。
  • 2    l    r 2~~l~~r 2  l  r:若该区间内有两个相同的数输出 1 1 1否则输出 0 0 0

解题思路

很好的一道题,之前在洛谷写过查询区间内是否有两数相同是用莫队维护的区间种类数,但是本题如果写莫队估计要 T L E TLE TLE,然后学到了这手很强的问题转化技巧:

对于区间内的每个数,我们只需要知道它右边离他最近相同数的在哪个位置,然后判断区间内的最小值是否在区间内。(或者等价的,查询每个数左边相同数的位置最大值是否在区间内)。那么这时删除一个数,只需要像双向链表那样删除就行,因此需要两个数组 L , R L,R L,R分别记录每个数最左边和最右边相邻的数,需要注意链表首尾节点的删除要特判一下,删除节点就单点更新其最右边的相同的数为无穷。

#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];void build(int i, int l, int r) { if (l == r) { tree[i] = R[l]; return; } int mid = (l + r) >> 1, 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, 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 mid = (l + r) >> 1, k = i << 1; if (y <= mid) return query(k, l, mid, x, y); else if (x > mid) return query(k | 1, mid + 1, r, x, y); else return min(query(k, l, mid, x, mid), query(k | 1, mid + 1, r, mid + 1, y));}int main() { ios::sync_with_stdio(0), cin.tie(0), cout.tie(0); int q, op, l, r; cin >> n >> q; memset(pre, 0x3f, sizeof pre); for (int i = 1; i <= n; i++) { cin >> a[i]; L[i] = pre[a[i]]; pre[a[i]] = i; } memset(pre, 0x3f, sizeof pre); for (int i = n; i >= 1; i--) R[i] = pre[a[i]], pre[a[i]] = i; //for (int i = 1; i <= n; i++) cout << L[i] << " "; cout << endl; //for (int i = 1; i <= n; i++) cout << R[i] << " "; cout << endl; build(1, 1, n); while (q--) { cin >> op; if (op == 1) { cin >> l; if (L[l] == inf) { if (R[l] != inf) { L[R[l]] = inf; } } else { if (R[l] == inf) { R[L[l]] = inf; change(1, 1, n, L[l], inf); } else { R[L[l]] = R[l]; L[R[l]] = L[l]; change(1, 1, n, L[l], R[l]); } } L[l] = R[l] = inf; change(1, 1, n, l, inf); } else { cin >> l >> r; int cur = query(1, 1, n, l, r); //cout << cur << " "; if (cur <= r) cout << "1" << endl; else cout << "0" << endl; } } return 0;}

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

你可能感兴趣的文章
MySQL 的 varchar 水真的太深了!
查看>>
mysql 的GROUP_CONCAT函数的使用(group_by 如何显示分组之前的数据)
查看>>
MySQL 的instr函数
查看>>
MySQL 的mysql_secure_installation安全脚本执行过程介绍
查看>>
MySQL 的Rename Table语句
查看>>
MySQL 的全局锁、表锁和行锁
查看>>
mysql 的存储引擎介绍
查看>>
MySQL 的存储引擎有哪些?为什么常用InnoDB?
查看>>
Mysql 知识回顾总结-索引
查看>>
Mysql 笔记
查看>>
MySQL 精选 60 道面试题(含答案)
查看>>
mysql 索引
查看>>
MySQL 索引失效的 15 种场景!
查看>>
MySQL 索引深入解析及优化策略
查看>>
MySQL 索引的面试题总结
查看>>
mysql 索引类型以及创建
查看>>
MySQL 索引连环问题,你能答对几个?
查看>>
Mysql 索引问题集锦
查看>>
Mysql 纵表转换为横表
查看>>
mysql 编译安装 window篇
查看>>