2019 CCPC 网络赛 HDU - 6703 array(线段树)

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

题意: n个数,m次查询,对于每个查询有两种操作:
操作1:将apos改为apos+10000000。
操作2:查询1~r中未出现过并且大于等于k的最小数。
思路:
因为数组中的值唯一,且在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 )的在线算法,可以较快地通过此题。

#include<bits/stdc++.h>
using namespace std;
#define lson (rt<<1)
#define rson ((rt<<1)|1)
const int MAXN = 100010;
const int INF = (1<<30);
int tree[MAXN<<2];
int a[MAXN];
int ans,t;

void build(int rt,int L,int R,int x,int w)
{
    if(L == R){
        tree[rt] = w;
        return;
    }
    int Mid = (L+R)>>1;
    if(x<=Mid)  build(lson,L,Mid,x,w);
    else build(rson,Mid+1,R,x,w);
    tree[rt] = max(tree[lson],tree[rson]);
}

void query(int rt,int L,int R,int l,int r,int w)
{
    if(l <= L && R <= r){
        if(t)   return ;
        if(L == R){
            if(tree[rt] > w){
                t = 1;
                ans = L;
            }
            return ;
        }
        int Mid = (L+R)>>1;
        if(tree[lson] > w)   query(lson,L,Mid,l,r,w);
        else if(tree[rson] > w)  query(rson,Mid+1,R,l,r,w);
        return ;
    }
    int Mid = (L+R)>>1;
    if(l <= Mid)    query(lson,L,Mid,l,r,w);
    if(Mid < r) query(rson,Mid+1,R,l,r,w);
}

void init(int n)
{
    for(int i = 1; i <= 4*n+10; ++i)   tree[i] = 0;
}

int main()
{
    int T;
    scanf("%d",&T);
    while(T--){
        int n,m;
        ans = 0;
        scanf("%d%d",&n,&m);
        init(n);
        for(int i = 1; i <= n; ++i){
            scanf("%d",&a[i]);
            build(1,1,n+1,a[i],i);
        }
        build(1,1,n+1,n+1,INF);
        while(m--){
            int x;
            scanf("%d",&x);
            if(x == 1){
                int y;  scanf("%d",&y);
                y = y ^ ans;
                build(1,1,n+1,a[y],INF);
            }
            else{
                t = 0;
                int r,k;
                scanf("%d%d",&r,&k);
                r = r ^ ans;    k = k ^ ans;
                query(1,1,n+1,k,n+1,r);
                printf("%d\n",ans);
            }
        }
    }
    return 0;
}

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值