CCPC网络赛-补

1002 array

array

Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 262144/262144 K (Java/Others)
Total Submission(s): 1382    Accepted Submission(s): 534


 

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

思路 

 因为数组中的值唯一,且在1到n的范围内,而询问的r和k也在1到n的范围内, 所以对于任意一个被操作1修改过的值都不会成为询问的答案,而询问的结果也必然在k到n+1的范围内。

因为没有被修改过值是唯一的,所以可以建立权值线段树,维护权值区间内的值所在下标的最大值;询问则转化为不小于k的值里面,下标超过r的最小权值是多少。

如何处理询问呢,一种较为暴力的解法是直接在线段树上询问权值在k到n+1的范围内第一个下标超过r的权值是多少。但复杂度可能会被卡,需要减枝。

再加上一个额外的判断就可以了,就是在递归查询完左子树内存不存在大于r的下标之后,如果不存在,则先看一下右子树内的下标的最大值是否大于r。如果不大于r,则不必再进入右子树内查询,否则答案一定在右子树内。

在进左子树之前也利用同样的判断条件来判断是否有必要进入左子树,这样做可以保证单次查询的复杂度是O(log n) 的。 而对于操作1,则等价于修改某个权值的下标为无穷大。操作复杂度也是O(log n )的。 综上所述,得到了一个复杂度为O( m * log n )的在线算法,可以较快地通过此题

/**
因为数组中的值唯一,且在1到n的范围内,而询问的r和k也在1到n的范围内。 所以对于任意一个被操
作1修改过的值都不会成为询问的答案,而询问的结果也必然在k到n+1的范围内。 因为没有被修改过
值是唯一的,所以可以建立权值线段树,维护权值区间内的值所在下标的最大值。而询问则转化为不小
于k的值里面,下标超过r的最小权值是多少。 如何处理询问呢,一种较为暴力的解法是直接在线段树上
询问权值在k到n+1的范围内第一个下标超过r的权值是多少。
**/
#include <cstdio>
#include <stack>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <iostream>
#include <map>
#include <vector>
#include <queue>
#include <set>
#define eps 1e-8
typedef long long ll;
const double PI = acos(-1.0);
const int maxn = 1e6;
const int INF = 0x3f3f3f;
const ll linf = 0x3f3f3f3f3f3f3f3f;
const int mod = 1e9+7;
using namespace std;
int n,m;
int a[maxn];
struct node
{
    int l,r;
    int mx;
}tr[maxn<<2];
void pushup(int pos)
{
    tr[pos].mx = max(tr[pos<<1].mx,tr[pos<<1|1].mx);
}
void build(int pos,int l,int r)
{
    tr[pos].l = l;
    tr[pos].r = r;
    if(l == r)
    {
        tr[pos].mx = 0;
        return;
    }
    int mid = (l+r)>>1;
    build(pos<<1,l,mid);
    build(pos<<1|1,mid+1,r);
    pushup(pos);
}
void add(int pos,int idx,int x)
{
    if(tr[pos].l == tr[pos].r)
    {
        tr[pos].mx = x;
        return;
    }
    int mid = (tr[pos].l+tr[pos].r)>>1;
    if(idx<=mid)
        add(pos<<1,idx,x);
    else
        add(pos<<1|1,idx,x);
    pushup(pos);
}
int query11(int pos,int k)
{
    if(tr[pos].l == tr[pos].r)
        return tr[pos].l;
    if(tr[pos<<1].mx>=k)
        return query11(pos<<1,k);
    else
        return query11(pos<<1|1,k);
}
int query1(int pos,int L,int R,int k)
{
    if(L>R)
        return -1;
    if(tr[pos].l>R || tr[pos].r<L)
        return -1;
    if(tr[pos].l>=L && tr[pos].r<=R)
    {
        if(tr[pos].mx>=k)
            return query11(pos,k);
        return -1;
    }
    int ans = query1(pos<<1,L,R,k);
    if(ans == -1)
        ans = query1(pos<<1|1,L,R,k);
    return ans;
}
int main()
{
    //ios::sync_with_stdio(false);
    int T;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d%d",&n,&m);
        build(1,1,n+1);
        for(int i = 1; i<=n; i++)
        {
            scanf("%d",&a[i]);
            add(1,a[i],i-1);
        }
        add(1,n+1,n+1);
        int op,x,y,last = 0;
        for(int i = 1; i<=m; i++)
        {
            scanf("%d",&op);
            if(op == 1)
            {
                scanf("%d",&x);
                x ^= last;
                add(1,a[x],n+1);
            }
            else
            {
                scanf("%d%d",&x,&y);
                x ^= last;
                y ^= last;
                last = query1(1,y,n+1,x);
                cout<<last<<endl;
            }
        }
    }

    return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值