题目大意:给定一个 N 个数字的排列,需要支持两种操作:对某个位置的数字 + 1e7,查询区间 [1, r] 中最小的不等于区间中任何一个数字的数。

题解:本题证明了对于 50W 的数据来说,\(O(nlog^2n)\) 的算法是过不去的。。

首先,最暴力的做法就是树状数组套权值线段树,实现了支持单点修改的主席树功能,但是复杂度爆炸了。

  1. 题目中所给的排列这一条件,可知没有两个数字是相同的。
  2. 由于询问的 k 小于 N,因此单点修改操作可以看成是删除了那个位置的数字。因此,可以发现答案一定在区间 [k, n + 1] 中。

解法1:

利用性质一,在序列上建立主席树,并增加一个 set,用来记录所有被删除的数字。每次询问时,可以询问区间 [r + 1, n + 1] 中大于 K 的最小值是多少,同时,在 set 中也二分一个大于 k 的最小值。可知,两者中最小的就是答案。

代码如下

  1. #include <bits/stdc++.h>
  2. using namespace std;
  3. const int maxn = 1e5 + 10;
  4. int n, m, a[maxn];
  5. set<int> s;
  6. struct node {
  7. #define ls(o) t[o].lc
  8. #define rs(o) t[o].rc
  9. int lc, rc, sz;
  10. } t[maxn * 20];
  11. int tot, rt[maxn];
  12. void insert(int &o, int p, int l, int r, int pos) {
  13. o = ++tot;
  14. t[o] = t[p];
  15. if (l == r) {
  16. t[o].sz++;
  17. return;
  18. }
  19. int mid = l + r >> 1;
  20. if (pos <= mid) {
  21. insert(ls(o), ls(p), l, mid, pos);
  22. } else {
  23. insert(rs(o), rs(p), mid + 1, r, pos);
  24. }
  25. t[o].sz = t[ls(o)].sz + t[rs(o)].sz;
  26. }
  27. int query(int o, int p, int l, int r, int k) {
  28. if (l == r) {
  29. return l;
  30. }
  31. int mid = l + r >> 1;
  32. int lsz = t[ls(o)].sz - t[ls(p)].sz, rsz = t[rs(o)].sz - t[rs(p)].sz;
  33. int ret = -1;
  34. if (k <= mid && lsz != 0) {
  35. ret = query(ls(o), ls(p), l, mid, k);
  36. }
  37. if (ret != -1) {
  38. return ret;
  39. }
  40. if (rsz != 0) {
  41. ret = query(rs(o), rs(p), mid + 1, r, k);
  42. }
  43. return ret;
  44. }
  45. void read() {
  46. scanf("%d %d", &n, &m);
  47. for (int i = 1; i <= n; i++) {
  48. scanf("%d", &a[i]);
  49. insert(rt[i], rt[i - 1], 1, n + 1, a[i]);
  50. }
  51. insert(rt[n + 1], rt[n], 1, n + 1, n + 1);
  52. }
  53. void solve() {
  54. int lastans = 0;
  55. while (m--) {
  56. static int opt;
  57. scanf("%d", &opt);
  58. if (opt == 1) {
  59. static int pos;
  60. scanf("%d", &pos);
  61. pos ^= lastans;
  62. s.insert(a[pos]);
  63. } else {
  64. static int r, k;
  65. scanf("%d %d", &r, &k);
  66. r ^= lastans, k ^= lastans;
  67. int ret = query(rt[r], rt[n + 1], 1, n + 1, k);
  68. auto it = s.lower_bound(k);
  69. if (it != s.end()) {
  70. ret = min(ret, *it);
  71. }
  72. printf("%d\n", ret);
  73. lastans = ret;
  74. }
  75. }
  76. }
  77. void initial() {
  78. for (int i = 1; i <= tot; i++) {
  79. t[i].lc = t[i].rc = t[i].sz = 0;
  80. }
  81. for (int i = 1; i <= n + 1; i++) {
  82. rt[i] = 0;
  83. }
  84. tot = 0;
  85. s.clear();
  86. }
  87. int main() {
  88. int T;
  89. scanf("%d", &T);
  90. while (T--) {
  91. initial();
  92. read();
  93. solve();
  94. }
  95. return 0;
  96. }

解法二:

根据性质二,可知答案区间一定是连续的。考虑建立权值线段树,维护序列下标的最大值。对于每次查询,转化成查询区间 [k, n + 1] 中下标大于 r 的最小权值。

代码如下

  1. #include <bits/stdc++.h>
  2. using namespace std;
  3. const int maxn = 1e5 + 10;
  4. int n, m, a[maxn];
  5. struct node {
  6. #define ls(o) t[o].lc
  7. #define rs(o) t[o].rc
  8. int lc, rc, mx;
  9. } t[maxn << 1];
  10. int tot, rt;
  11. inline void pull(int o) {
  12. t[o].mx = max(t[ls(o)].mx, t[rs(o)].mx);
  13. }
  14. void insert(int &o, int l, int r, int pos, int val) {
  15. if (o == 0) {
  16. o = ++tot;
  17. }
  18. if (l == r) {
  19. t[o].mx = val;
  20. return;
  21. }
  22. int mid = l + r >> 1;
  23. if (pos <= mid) {
  24. insert(ls(o), l, mid, pos, val);
  25. } else {
  26. insert(rs(o), mid + 1, r, pos, val);
  27. }
  28. pull(o);
  29. }
  30. void modify(int o, int l, int r, int pos) {
  31. if (l == r) {
  32. t[o].mx = 1e9;
  33. return;
  34. }
  35. int mid = l + r >> 1;
  36. if (pos <= mid) {
  37. modify(ls(o), l, mid, pos);
  38. } else {
  39. modify(rs(o), mid + 1, r, pos);
  40. }
  41. pull(o);
  42. }
  43. int query(int o, int l, int r, int x, int y) { // x -> [x, n + 1] y -> >= y
  44. if (l == r) {
  45. return l;
  46. }
  47. int mid = l + r >> 1;
  48. int ret = -1;
  49. if (x <= mid && t[ls(o)].mx >= y) {
  50. ret = query(ls(o), l, mid, x, y);
  51. }
  52. if (ret != -1) {
  53. return ret;
  54. }
  55. if (t[rs(o)].mx >= y) {
  56. ret = query(rs(o), mid + 1, r, x, y);
  57. }
  58. return ret;
  59. }
  60. void read() {
  61. scanf("%d %d", &n, &m);
  62. for (int i = 1; i <= n; i++) {
  63. scanf("%d", &a[i]);
  64. insert(rt, 1, n + 1, a[i], i);
  65. }
  66. a[n + 1] = n + 1;
  67. insert(rt, 1, n + 1, n + 1, n + 1);
  68. }
  69. void solve() {
  70. int lastans = 0;
  71. while (m--) {
  72. static int opt;
  73. scanf("%d", &opt);
  74. if (opt == 1) {
  75. static int pos;
  76. scanf("%d", &pos);
  77. pos ^= lastans;
  78. modify(rt, 1, n + 1, a[pos]);
  79. } else {
  80. static int r, k;
  81. scanf("%d %d", &r, &k);
  82. r ^= lastans;
  83. k ^= lastans;
  84. lastans = query(rt, 1, n + 1, k, r + 1);
  85. printf("%d\n", lastans);
  86. }
  87. }
  88. }
  89. void initial() {
  90. for (int i = 1; i <= tot; i++) {
  91. t[i].lc = t[i].rc = t[i].mx = 0;
  92. }
  93. rt = tot = 0;
  94. }
  95. int main() {
  96. int T;
  97. scanf("%d", &T);
  98. while (T--) {
  99. initial();
  100. read();
  101. solve();
  102. }
  103. return 0;
  104. }

【HDU6703】array的更多相关文章

  1. 题解【UVA12003】Array Transformer

    题目描述 输入输出格式 输入格式 输出格式 输入输出样例 输入样例#1 10 1 11 1 2 3 4 5 6 7 8 9 10 2 8 6 10 输出样例#1 1 2 3 4 5 6 7 8 9 6 ...

  2. 【Java】Array 数组

    概述 数组是多个相同数据类型按一定顺序排列的一组数据 特点: - 数据类型相同!! - 长度固定!! 构成数组的几个要素 - 数组名称 - 下标,又称索引 - 元素 - 数组长度 数组是一种引用类型, ...

  3. 【总结】Array、ArrayList、List

    一.Array(数组) 1.申明时必须要指定数组长度. 2.数据类型安全. 申明数组如下: 1 class Program 2 { 3 static void Main(string[] args) ...

  4. 【C++】array初始化0

    让代码...优雅? ==================分割线==================== 局部数组:没有默认值,如果声明的时候不定义,则会出现随机数(undefined):如果声明的长度 ...

  5. 【R】array 2 string

    paste(1:10, collapse = '') http://stackoverflow.com/questions/2098368/how-do-i-concatenate-a-vector- ...

  6. 【CF1023D】Array Restoration(构造,线段树)

    题意:有一个长为n的序列,对其进行q次操作,第i次操作可以把连续的一段覆盖为i 现在给出操作后的序列,第i个数字为a[i],其中有一些为0的位置可以为任意值,要求构造任意一组合法的操作后的序列 无解输 ...

  7. 【CF1068D】Array Without Local Maximums(计数DP)

    题意: n<=1e5 思路:卡内存 dp[i][j][k]表示当前第i个数字为j,第i-1个数字与第i个之间大小关系为k的方案数(a[i-1]<a[i],=,>) 转移时使用前缀和和 ...

  8. 【LeetCode】Array

    [11] Container With Most Water [Medium] O(n^2)的暴力解法直接TLE. 正确的解法是Two Pointers. O(n)的复杂度.保持两个指针i,j:分别指 ...

  9. 【计数dp】Array Without Local Maximums

    参考博客:[CF1068D]Array Without Local Maximums(计数DP) [题意] n<=1e5 dp[i][j][k]表示当前第i个数字为j,第i-1个数字与第i个之间 ...

随机推荐

  1. 【AMAD】dogpile.cache -- 一个Python缓存API,提供一套通用的接口来适配不同的缓存后端

    简介 动机 作用 用法 个人评分 简介 Dogpile1由两套子系统组成,其中一个是基于另一个来构建的. dogpile提供了dogpile lock的概念,这个控制结构让一个线程可以被选为一些资源的 ...

  2. 二 MyBatis 从入门到进阶 2 Maven 入门

    1 Maven 的使用 1.1 本地仓库与中央仓库 本地仓库:Window \ Preferences \ Maven \ User Settings \ Local Repository 中央仓库: ...

  3. python 连接SQL SERVER 并读取其数据

    1.没什么难的操作 安装  pip install pymssql import pymssql #引入pymssql模块 import pandas as pd def conn(): connec ...

  4. python random 的用法

    python random的里面的方法其实是Random实例化的对象. 里面几个常用的几个方import random print( random.randint(1,10) ) # 产生 1 到 1 ...

  5. [转帖]浪潮信息最大供应商英特尔(Intel):2018 年采购额 145.76 亿元

    浪潮信息最大供应商英特尔(Intel):2018 年采购额 145.76 亿元 https://t.cj.sina.com.cn/articles/view/3172142827/bd130eeb01 ...

  6. python 求从1加到100的和,join的用法

    li=[] def func3(x): li.append(str(x)) if x==1: return 1 return x+func3(x-1) # print(func3(100)) re=f ...

  7. springboot整合springdatajpa时jar冲突

    1.springboot整合springdatajpa测试时报No bean named 'entityManagerFactory' available错误 2.运行springboot主程序时报以 ...

  8. Spring添加声明式事务

    一.前言 Spring提供了声明式事务处理机制,它基于AOP实现,无须编写任何事务管理代码,所有的工作全在配置文件中完成. 二.声明式事务的XML配置方式 为业务方法配置事务切面,需要用到tx和aop ...

  9. C++ 的关键字(保留字)完整介绍

    转载至:https://www.runoob.com/w3cnote/cpp-keyword-intro.html 1. asm asm (指令字符串):允许在 C++ 程序中嵌入汇编代码. 2. a ...

  10. 版本控制器之SVN(二)

    安装重启以后,在菜单栏找到TortoiseSVN程序 启动以后 点击: 填写相应的信息: 可以看到项目的相关信息 选中仓库,右键 > Browse Repository 进入如下界面: 可以打开 ...