博客
关于我
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 - 视图
查看>>
MySQL - 解读MySQL事务与锁机制
查看>>
MTTR、MTBF、MTTF的大白话理解
查看>>
mt_rand
查看>>
mysql /*! 50100 ... */ 条件编译
查看>>
mudbox卸载/完美解决安装失败/如何彻底卸载清除干净mudbox各种残留注册表和文件的方法...
查看>>
mysql 1264_关于mysql 出现 1264 Out of range value for column 错误的解决办法
查看>>
mysql 1593_Linux高可用(HA)之MySQL主从复制中出现1593错误码的低级错误
查看>>
mysql 5.6 修改端口_mysql5.6.24怎么修改端口号
查看>>
MySQL 8.0 恢复孤立文件每表ibd文件
查看>>
MySQL 8.0开始Group by不再排序
查看>>
mysql ansi nulls_SET ANSI_NULLS ON SET QUOTED_IDENTIFIER ON 什么意思
查看>>
multi swiper bug solution
查看>>
MySQL Binlog 日志监听与 Spring 集成实战
查看>>
MySQL binlog三种模式
查看>>
multi-angle cosine and sines
查看>>
Mysql Can't connect to MySQL server
查看>>
mysql case when 乱码_Mysql CASE WHEN 用法
查看>>
Multicast1
查看>>
MySQL Cluster 7.0.36 发布
查看>>