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. Mysql带条件取多条随机记录

    有个文章段落表part,有两种类型的段落,即part_type取1或2,要从表中随机取多条任意类型的段落,比如3条. 方法一 ORDER BY后接RAND() select * from part w ...

  2. 让 KEPServer 变成一款 Web 组态软件

    ​KEPServerEX是行业领先的连接平台,用于向您的所有应用程序提供单一来源的工业自动化数据.该平台的设计使用户能够通过一个直观的用户界面来连接.管理.监视和控制不同的自动化设备和软件应用程序. ...

  3. golang url解析

    package main import "fmt" import "net/url" import "strings" func main( ...

  4. gin框架对接快递100 查询快递跟踪记录 Golang实现快递查询

    参考ui效果: https://www.kuaidi100.com/?from=openv gin框架: 请求地址 http://localhost:8822/kd100/auto_com_num?n ...

  5. SpringBoot-Http请求工具类

    一.编写请求配置类 import com.alibaba.fastjson.JSONObject; import org.springframework.context.annotation.Conf ...

  6. leaflet 实现地图上标记的发散闪烁动画

    先看效果 js文件:blinkmarker.js L.blinkMarker = function (point, property) { // 使用js标签,便于操作,这个temDivEle的作用是 ...

  7. C数据结构:二叉树的基本操作

    二叉树 树基本知识 二叉树的性质 满二叉树 完全二叉树 性质4.5的解释 顺序存储结构(利用性质4.5) 链式存储结构 结点结构体 建立二叉树 先序遍历 中序遍历 后序遍历 层次遍历 复制二叉树 计算 ...

  8. 5GC 关键技术之 MEC 边缘计算

    目录 文章目录 目录 前文列表 MEC 边缘计算 ETSI MEC 标准化参考模型 MEC 架构设计原则 MEC 分层架构 MEC 系统架构 MEC 软件架构 MEC in NFV 融合架构 ETSI ...

  9. AIRIOT答疑第3期|如何使用物联网平台的可视化组态引擎?

    丰富组件,满足千人千面! AIRIOT物联网低代码平台的可视化组态引擎,具备丰富的可视化看板及组件,满足各类工艺流程图.数据可视化需求.支持三维编辑.图形绘制.图表设计等设计方式,PPT模式设计软件界 ...

  10. form-create-designer-naiveui

    这个是 Vue3 版本 form-create-designer-naiveui 是基于 @form-create/naive-ui vue3版本实现的表单设计器组件.可以通过拖拽的方式快速创建表单, ...