HDOJ 6703 Array

题目

题目链接

array

*Time Limit: 4000/2000 MS (Java/Others) Memory Limit: 262144/262144 K (Java/Others)

Total Submission(s): 3577 Accepted Submission(s): 1323

*

Problem Description

You are given an array a1,a2,...,an(∀i∈[1,n],1≤ai≤n). Initially, each element of the array is unique.

Moreover, there are m instructions.

Each instruction is in one of the following two formats:

\1. (1,pos),indicating to change the value of apos to apos+10,000,000;

\2. (2,r,k),indicating to ask the minimum value which is not equal to any ai ( 1≤i≤r ) and **not less ** than k.

Please print all results of the instructions in format 2.

Input

The first line of the input contains an integer T(1≤T≤10), denoting the number of test cases.

In each test case, there are two integers n(1≤n≤100,000),m(1≤m≤100,000) in the first line, denoting the size of array a and the number of instructions.

In the second line, there are n distinct integers a1,a2,...,an (∀i∈[1,n],1≤ai≤n),denoting the array.

For the following m lines, each line is of format (1,t1) or (2,t2,t3).

The parameters of each instruction are generated by such way :

For instructions in format 1 , we defined pos=t1⊕LastAns . (It is promised that 1≤pos≤n)

For instructions in format 2 , we defined r=t2⊕LastAns,k=t3⊕LastAns. (It is promised that 1≤r≤n,1≤k≤n )

(Note that ⊕ means the bitwise XOR operator. )

Before the first instruction of each test case, LastAns is equal to 0 .After each instruction in format 2, LastAns will be changed to the result of that instruction.

(∑n≤510,000,∑m≤510,000 )

Output

For each instruction in format 2, output the answer in one line.

Sample Input

3
5 9
4 3 1 2 5
2 1 1
2 2 2
2 6 7
2 1 3
2 6 3
2 0 4
1 5
2 3 7
2 4 3
10 6
1 2 4 6 3 5 9 10 7 8
2 7 2
1 2
2 0 5
2 11 10
1 3
2 3 2
10 10
9 7 5 3 4 10 6 2 1 8
1 10
2 8 9
1 12
2 15 15
1 12
2 1 3
1 9
1 12
2 2 2
1 9

Sample Output

1
5
2
2
5
6
1
6
7
3
11
10
11
4
8
11

Hint

note:

After the generation procedure ,the instructions of the first test case are :

2 1 1, in format 2 and r=1 , k=1

2 3 3, in format 2 and r=3 , k=3

2 3 2, in format 2 and r=3 , k=2

2 3 1, in format 2 and r=3 , k=1

2 4 1, in format 2 and r=4 , k=1

2 5 1, in format 2 and r=5 , k=1

1 3 , in format 1 and pos=3

2 5 1, in format 2 and r=5 , k=1

2 5 2, in format 2 and r=5 , k=2

the instructions of the second test case are :

2 7 2, in format 2 and r=7 , k=2

1 5 , in format 1 and pos=5

2 7 2, in format 2 and r=7 , k=2

2 8 9, in format 2 and r=8 , k=9

1 8 , in format 1 and pos=8

2 8 9, in format 2 and r=8 , k=9

the instructions of the third test case are :

1 10 , in format 1 and pos=10

2 8 9 , in format 2 and r=8 , k=9

1 7 , in format 1 and pos=7

2 4 4 , in format 2 and r=4 , k=4

1 8 , in format 1 and pos=8

2 5 7 , in format 2 and r=5 , k=7

1 1 , in format 1 and pos=1

1 4 , in format 1 and pos=4

2 10 10, in format 2 and r=10 , k=10

1 2 , in format 1 and pos=2

Source

2019中国大学生程序设计竞赛(CCPC) - 网络选拔赛

分析

大概意思是给定一个数组, 有两个操作.

  • OP1: 把数组中的某个位置上的数加上一个很大的值.

  • OP2: 问数组中和前r个数都不一样, 但大于等于k的最小的数是什么.

这是一道非常典型的, 难度不大, 但有非常明显的人工埋坑痕迹的题目.

  • 第一坑 数据范围

    先看数组a的数据的范围 $ a \in [1,n] $ 且另有限制条件数组\(a\)中每一个数唯一, 这隐性表示了\(a\)是1到n的一个排列 .

    再看修改和查询两个操作的数值范围, 也都被限制在了 \([1,n]\) 之间. 也就是说, 所有的操作都会是在\(1-n\)上进行的.

    这些细节暗示了我们可以将这个问题进行简化.

  • 第二坑 r/k动态计算

    这里的\(r\)和\(k\)不是直接获得的, 而会根据上一个输出的答案进行异或\(XOR\)得到的.

    一般这么设计的目的都是为了限制使用离线算法, 但这题这么设计的目的其实是想让计算过程变的很不直观, 让你琢磨不透到底进行的是什么操作.

    尽管\(r\)和\(k\)都需要经\(XOR\)处理后才能得到, 但题目中还是特意让处理后的\(r\)和\(k\)都落在\([1,n]\)之间, 说明\([1,n]\)这个限制一定非常重要, 解题的时候非用不可.

  • 第三坑 故弄玄虚

    再细看OP1, 对数组中的某个数加上 10,000,000 .

    这个值其实很有讲究, 首先这个数设计的非常随意, 就像是1后面随便按了几个0, 每个位置上的数都加上这么一个同样的数, 也说明了这个值其实并不重要.

    其次, 10,000,000 这个数字太大了, 大过了\(n\)和\(m\)的最大值. 加上这么一个数之后, 基本上这个数字就走远了, 再结合 \(r\) 和\(k\) 都被限制在了\([1,n]\)之间, OP2中的查询已经管不到它了. 其实就暗示了OP1根本就是一个无用操作, 是为了把人绕晕而专门设计的.

分析完这三个坑之后, 再来看一下这题是怎么解的. 首先, 来分析一下这些操作到底是在做什么.

以数组 \(a = [4~3~1~2~5]\) 为例子

OP2的输入: \(r=3, k=3\) (这里的假设\(r,k\)都已经被换成了真实的查询) 就是要排除掉 4,3,1 后找第一个大于等于3的数字, 这里可以找到数字5.

OP2的输入: \(r=3, k=2\) 排除掉 4,3,1 后找第一个大于等2的数字, 这里可以找到数字2.

这里的\(r\)限制了数组\(a\)中需检测的范围, 数组\(a\)在\(1\ldots r\)中的值是离散的, 而阈值\(k\) 又卡掉了一部分数字, 这两个限制会让这个问题非常不好处理.

考虑到数组\(a\)其实是\([1,n]\)的一个排列, 我们将其换一种形式来表示.

设数组\(t\)中的\(t[i]\)表示第\(i\)个数出现的位置.

对应数组\(a\)可以转换成数组\(t\)为: \([3~4~2~1~5]\) , 它的含义为第1个数出现在位置3, 第2个数出现在位置4 \(\ldots\)

现在, OP2就可以表示为在数组\(t\)上, 从第\(k\)位开始到结束, 值大于\(r\)的位置上最小下标是什么.

这样我们就可以跳过转换前数组\(a\)中\([1,r]\)之间的数都是离散的状况.

再来看OP1, 数组\(a\)中任何数字加上一个很大值之后都会走的很远, 而\(k\)最大也就为\(n\), 所以\(n+1\)可以是一个默认答案.

解法

可以将数组\(t\)最后附加一个\(n+1\), 并构建一棵线段树.

我们从根节点往下递归:

  • 限制1: 数组的下标要大于等于\(k\)(见代码Line-58).

  • 限制2: 最终的位置上的值要大于\(r\)(见代码Line-62).

OP2的就是满足这两个条件下的数组\(t\)中最靠左的位置的下标.

但限制2并没有什么规律, 这个递归过程很可能要把下标大于\(k\)的半个子树都遍历一遍, 会导致超时.

因此, 还需要两个优化:

  1. 能在左子树上找到结果, 就不用再到右子树上找 (见代码 Line-54 和 Line-76)
  2. 对树上的每个结点维护一个值来记录这个节点下的子树中能存在的最大下标是多少. 如果最大的下标都还少于\(r\), 就不用再往下找下去了, 肯定不满足限制2

再看操作1, 我们只需要把数组中的这个位置上值更新成\(n+1\), 表示该数字已经远去就可以了, 毕竟\(n+1\)总会是一个可能的答案.

代码

#define _CRT_SECURE_NO_WARNINGS

#include <iostream>
#include <cmath>
#include <algorithm> using namespace std; const int maxn = 100100; int la = 0;
int n,m;
int a[maxn]; int rt;
int val[maxn<<2]; void tree_init(int l,int r,int root)
{
// 需要优化
//memset(val,0,sizeof(val));
val[root]=0;
if(l==r) return;
int m=(l+r)/2;
tree_init(l,m,root<<1);
tree_init(m+1,r,root<<1|1);
} void tree_insert(int l, int r,int root, int pos, int v)
{
if(l==r)
{
val[root]=v;
return ;
}
int m = (l+r)/2;
if(pos<=m)
{
tree_insert(l,m,root<<1,pos,v);
}
else
{
tree_insert(m+1,r,root<<1|1,pos,v);
}
//
val[root] = max(val[root<<1],val[root<<1|1]);
} int query_results; bool tree_query(int l, int r, int root, int KK, int RR)
{
if(l>query_results)
{
return true;
}
if(r<KK)
{
return false;
}
if(val[root]<=RR)
{
return false;
}
if(l==r)
{
query_results = min(query_results, l);
return true;
}
int m = (l+r)/2;
// l...m
bool is_find = false;
is_find = tree_query(l,m,root<<1,KK,RR);
// m+1, r
if(is_find==false)
{
is_find = tree_query(m+1,r,root<<1|1,KK,RR);
}
return is_find;
}
void debug_tree(int l, int r, int root)
{
printf("%2d: [%d---%d] val: %d\n",root,l,r,val[root]);
if(l==r) return ;
int m = (l+r)/2; debug_tree(l,m,root<<1);
debug_tree(m+1,r,root<<1|1);
} int main()
{
int T;
scanf("%d",&T);
while(T--)
{
scanf("%d%d",&n,&m);
tree_init(1,n+1,1);
la = 0;
for(int i=0;i<n;i++)
{
scanf("%d",&a[i]);
// a[i] 出现在 第i号 位置
tree_insert(1,n+1,1,a[i],i+1);
}
/*
tree_insert(1,n+1,1,n+1,n+1);
debug_tree(1,n+1,1);
query_results = n+1;
tree_query(1,n+1,1,4,3);
printf("find: %d\n",query_results);
*/
for(int i=0;i<m;i++)
{
int t, pos, rr, kk;
scanf("%d",&t);
if(t==1)
{
scanf("%d",&pos);
pos = pos^la;
//printf("op1: pos: %d\n",pos);
if(a[pos-1]==-1) continue;
tree_insert(1,n+1,1,a[pos-1],n+1);
a[pos-1]=-1;
//debug_tree(1,n+1,1);
}
else if(t==2)
{
scanf("%d%d",&rr,&kk);
rr = rr^la;
kk = kk^la;
query_results = n+1;
tree_query(1,n+1,1,kk,rr);
//printf("op2: r: %d k: %d find: %d\n",rr,kk,query_results);
la = query_results;
printf("%d\n",query_results);
}
}
} return 0;
}

链接:

http://www.codebonobo.tech/post/b0002_hdoj6703/

HDOJ 6703 Array的更多相关文章

  1. 2019年CCPC网络赛 HDU 6703 array【权值线段树】

    题目大意:给出一个n个元素的数组A,A中所有元素都是不重复的[1,n].有两种操作:1.将pos位置的元素+1e72.查询不属于[1,r]中的最小的>=k的值.强制在线. 题解因为数组中的值唯一 ...

  2. hdu 6703 array(权值线段树)

    Problem Description You are given an array a1,a2,...,an(∀i∈[1,n],1≤ai≤n). Initially, each element of ...

  3. CCPC 2019 网络赛 1002 array (权值线段树)

    HDU 6703 array   题意:   给定一个数组 \(a_1,a_2, a_3,...a_n\) ,满足 \(1 \le a[i]\le n\) 且 \(a[i]\) 互不相同.   有两种 ...

  4. 2019CCPC网络预选赛 八道签到题题解

    目录 2019中国大学生程序设计竞赛(CCPC) - 网络选拔赛 6702 & 6703 array 6704 K-th occurrence 6705 path 6706 huntian o ...

  5. 【HDOJ】5632 Rikka with Array

    1. 题目描述$A[i]$表示二级制表示的$i$的数字之和.求$1 \le i < j \le n$并且$A[i]>A[j]$的$(i,j)$的总对数. 2. 基本思路$n \le 10^ ...

  6. javascript中的Array对象 —— 数组的合并、转换、迭代、排序、堆栈

    Array 是javascript中经常用到的数据类型.javascript 的数组其他语言中数组的最大的区别是其每个数组项都可以保存任何类型的数据.本文主要讨论javascript中数组的声明.转换 ...

  7. ES5对Array增强的9个API

    为了更方便的对Array进行操作,ES5规范在Array的原型上新增了9个方法,分别是forEach.filter.map.reduce.reduceRight.some.every.indexOf ...

  8. JavaScript Array对象

    介绍Js的Array 数组对象. 目录 1. 介绍:介绍 Array 数组对象的说明.定义方式以及属性. 2. 实例方法:介绍 Array 对象的实例方法:concat.every.filter.fo ...

  9. 了解PHP中的Array数组和foreach

    1. 了解数组 PHP 中的数组实际上是一个有序映射.映射是一种把 values 关联到 keys 的类型.详细的解释可参见:PHP.net中的Array数组    . 2.例子:一般的数组 这里,我 ...

  10. 关于面试题 Array.indexof() 方法的实现及思考

    这是我在面试大公司时碰到的一个笔试题,当时自己云里雾里的胡写了一番,回头也曾思考过,最终没实现也就不了了之了. 昨天看到有网友说面试中也碰到过这个问题,我就重新思考了这个问题的实现方法. 对于想进大公 ...

随机推荐

  1. linux Makefile 如何将生成的 .o 文件放到指定文件夹

    一.Makefile文件 为了方便分析,直接上文件,Makefile 文件中的内容如下所示: # # Makefile # 编译的.o文件和.c文件在同一路径下 # $(info "star ...

  2. 在线程中使用Spring的Bean的方法、不推荐把“线程”注入到Spring

    一.不推荐把"线程"注入到spring 将线程注入到Spring容器中并不是一个常见的做法,而且通常也不推荐这样做,原因如下: 生命周期管理困难: Spring管理的Bean生命周 ...

  3. VSCode+VUE+ESLint以达到保存自动格式化

    首先打开VSCode在.eslintrc.js中加入以下代码(不知道怎么找可以ctrl+shift+p进行搜索),添加 vscode 终端启动服务 // 添加⾃定义规则 'prettier/prett ...

  4. docker-compose 配置LNMP环境

    仓库地址: https://gitee.com/haima1004/docker-lnmp 参考文档: 视频地址: https://www.bilibili.com/video/BV1S54y1B7K ...

  5. Critical Expression

    什么是Critical Expression 所谓Critical Expression就是一个表达式依赖的值,必须出现在这个表达式前面.比如: times (label-$) db 0 ;times ...

  6. Go-Zero定义API实战:探索API语法规范与最佳实践(五)

    前言 上一篇文章带你实现了Go-Zero模板定制化,本文将继续分享如何使用GO-ZERO进行业务开发. 通过编写API层,我们能够对外进行接口的暴露,因此学习规范的API层编写姿势是很重要的. 通过本 ...

  7. 你知道 Java 有哪些引用吗?

    前言 判断对象是否要回收有引用计数法和可达性算法两种方式,无论哪种都离不开引用,本文将介绍Java的四种引用. 一.概述 二.详解 1. 强引用 概述 在Java程序中,强引用是最常见的也是默认的.n ...

  8. 智能控制 | AIRIOT智慧楼宇管理解决方案

    许多行业客户在智慧楼宇的建设中主要面临运营管理低效,楼宇内部各个系统相互独立,不仅管理操作复杂,而且各系统间的数据无法分享,无法支撑大数据分析.此外,由于楼宇管理系统的低效,50%的建筑能耗是被浪费的 ...

  9. IIS 部署 Python 环境

    1.安装IIS 勾选特殊CGI程序2.Python 环境 (环境变量配置)3.如果没有pip命令 先下载安装pip python setup.py install4.pip install wfast ...

  10. 食道测压结合Manoview软件

    我认为是位于食道开始的地方是上食道括约肌(UES):upper esophageal sphincte,吞咽时,此处的压力会有变大.食道结束的地方是食道下括约肌(LES),从这在往下就是胃,一般情况这 ...