HDU-6703 array (线段树)

题意

一个长度为n的排列a,\(\forall i\in [1,n] ,1\le a_i \le n\) , m次操作,每次操作:

  1. (1,pos),把 \(a_{pos}\) 变为\(a_{pos} + 10000000\)
  2. (2,r,k) ,找到最小的一个值x,使得\(\forall i\in [1,r], x \neq a_i, x\ge k\)

数据范围:

\(1\le n\le 100000,1\le m\le 100000,1\le r\le n,1\le k\le n\)

分析

  1. 观察每个数的值域,都在\([1,n]\) 之间,而k的范围也在\([1,n]\) 之间,所以答案最终只会在\([1,n+1]\) 之间。

  2. 操作1会使一个数字\(a_i\)加1e7,而这个数已经远远超过n和k,所以也就代表着\(a_i\)从原序列中被删除了。

  3. 由第一条可以知道,每次查询的答案只会在[k,n+1]上,而序列中的数只会在[1,n](进行过1操作的直接删除,不再考虑)。所以我们可以每次查询序列中有没有出现在\([k,n]\) 的数,并且他们的下标是大于r的。如果之前删除过一个数\(x\),那么就把这个下标变成大于n就可以了, 这样对于\(k\le x\) 的情况,\(x\) 所对应的下标都是大于\(r\) 的(也就是把x作为候选答案)

如何维护查询所需要的东西?权值线段树维护区间权值最大下标

  1. 对于操作1,直接让单点的下标变为n+1
  2. 对于操作2,找被区间[k,n]的包含的结点,对于这些结点,如果左节点的最大下标大于r,则递归左节点,否则看右结点,如果都没有,就返回n+1(代表答案候选为n+1)。而递归到终点时,看单点维护的下标是否大于r,如果大于,就返回单点的权值,否则返回n+1.
#include <bits/stdc++.h>
using namespace std;
const int N = 1e5+10;
const int inf = 0x3f3f3f3f;
int a[N],b[N];
struct SegTree{
    int l,r,id;
}t[4*N];
int n,m;
void build(int p,int l,int r){
    t[p].l = l;t[p].r = r;
    if(l == r){
        t[p].id = b[l];
        return;
    }
    int mid = l + r >> 1;
    build(p*2,l,mid);
    build(p*2+1,mid+1,r);
    t[p].id = max(t[p*2].id,t[p*2+1].id);
}
void change(int p,int x){
    if(t[p].l == t[p].r && t[p].l == x){
        t[p].id = n+1;return;//删除该数,将维护的下标变为n+1
    }
    int mid = t[p].l + t[p].r >> 1;
    if(x <= mid)change(p*2,x);
    else if(x > mid)change(p*2+1,x);
    t[p].id = max(t[p*2].id,t[p*2+1].id);
}
int query(int p,int l,int r,int x){
    if(t[p].l >= l && t[p].r <= r){//找到被[k,n]完全包含的结点
        if(t[p].l == t[p].r){
            if(t[p].id > x)
                return t[p].l;
            return n + 1;
        }
        if(t[p*2].id > x)return query(p*2,l,r,x);
        if(t[p*2+1].id > x)return query(p*2+1,l,r,x);
        return n + 1;
    }
    int mid = t[p].l + t[p].r >> 1;
    int res = n+1;
    if(mid >= l){
        res = query(p*2,l,r,x);
    }
    if(mid < r){
        res = min(res, query(p*2+1,l,r,x));
    }
    return res;
}
int main(){
    int T;scanf("%d",&T);
    while(T--){
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++)b[i] = 0;
        for(int i=1;i<=n;i++){
            scanf("%d",&a[i]);
            b[a[i]] = i;//因为时排列,每个a[i]都不一样
        }
        build(1,1,n);
        int res = 0;
        while(m--){
            int op,x,y;
            scanf("%d%d",&op,&x);
            if(op == 1){
                x ^= res;
                change(1,a[x]);
            }
            else{
                scanf("%d",&y);x^=res;y^=res;
                res = query(1,y,n,x);
                printf("%d\n",res);
            }
        }
    }
    return 0;
}

转载于:https://www.cnblogs.com/1625--H/p/11404011.html

1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。、可私 6信博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 、可私信6博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 、可私信6博主看论文后选择购买源代码。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值