HDU6703 array [权值线段树]

a r r a y array array

题目描述见链接 .


正 解 部 分 \color{red}{正解部分}

  • 1 1 1 操作, 等价于将对应位置的数字删除, 在下述 权值线段树 中把对应位置权值赋为 N + 1 N+1 N+1 即可 .
  • 2 2 2 操作, 首先可以发现答案 a n s ∈ [ 1 , N + 1 ] ans ∈ [1, N+1] ans[1,N+1],
    考虑怎么去寻找 大 于 等 于 k 且 尽 量 小 大于等于k且尽量小 k a n s   ! = a [ 1 , r ] ans\ !=a_{[1,r]} ans !=a[1,r] 的数字,
    建立下标属于 [ 1 , N + 1 ] [1,N+1] [1,N+1]权值线段树, 可以保证 a n s ans ans 一定可以从 权值线段树 中得到,
    权值线段树 的节点存下当前权值区间的 最右位置, 设为 m a x _ r max\_r max_r, N + 1 N+1 N+1位置的初值为 N + 1 N+1 N+1,
    往下递归查找 [ k , N + 1 ] [k,N+1] [k,N+1] 的区间时, 只需要检查 左子树 m a x _ r max\_r max_r 是否大于 r r r, 若大于, 说明有解, 往左子树走, 否则只能往 右子树 走 .

实 现 部 分 \color{red}{实现部分}

#include<bits/stdc++.h>
#define reg register

int read(){
        char c;
        int s = 0, flag = 1;
        while((c=getchar()) && !isdigit(c))
                if(c == '-'){ flag = -1, c = getchar(); break ; }
        while(isdigit(c)) s = s*10 + c-'0', c = getchar();
        return s * flag;
}

const int maxn = 100005;

int N;
int M;
int A[maxn];
int B[maxn];

struct Segment_Tree{ 

        struct Node{ int l, r, max_r; } T[maxn<<2];

        void Build(int k, int l, int r){
                T[k].l = l, T[k].r = r;
                if(l == r){ T[k].max_r = B[l]; return ; }
                int mid = l+r >> 1;
                Build(k<<1, l, mid), Build(k<<1|1, mid+1, r);
                T[k].max_r = std::max(T[k<<1].max_r, T[k<<1|1].max_r);
        }

        void Modify(int k, int aim_p, int aim_v){
                int l = T[k].l, r = T[k].r;
                if(l == r){ T[k].max_r = aim_v; return ; }
                int mid = l+r >> 1;
                if(aim_p <= mid) Modify(k<<1, aim_p, aim_v);
                else Modify(k<<1|1, aim_p, aim_v);
                T[k].max_r = std::max(T[k<<1].max_r, T[k<<1|1].max_r);
        }

        int Query(int k, int lim, int ql, int qr){
                int l = T[k].l, r = T[k].r;
                if(l == r) return l;
                int mid = l+r >> 1;
                int s = N + 1;
                if(ql <= mid && T[k<<1].max_r > lim) s = Query(k<<1, lim, ql, qr);
                if(s != N+1) return s;
                if(qr > mid && T[k<<1|1].max_r > lim) s = std::min(s, Query(k<<1|1, lim, ql, qr));
                return s;
        }

} seg_t;

void Work(){
        N = read(), M = read();
        for(reg int i = 1; i <= N; i ++) A[i] = read();
        for(reg int i = 1; i <= N; i ++) B[A[i]] = i;
        B[N+1] = N+1;
        seg_t.Build(1, 1, N+1);
        int last_ans = 0;
        for(reg int i = 1; i <= M; i ++){
                int opt = read();
                if(opt == 1){
                        int pos = read() ^ last_ans;
                        if(A[pos] == N+1) continue ;
                        seg_t.Modify(1, A[pos], N+1);
                        A[pos] = N+1;
                }else{
                        int r = read() ^ last_ans, k = read() ^ last_ans;
                        printf("%d\n", last_ans = seg_t.Query(1, r, k, N+1));
                }
        }
}

int main(){
        int T_num = read();
        while(T_num --) Work();
        return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
提供的源码资源涵盖了安卓应用、小程序、Python应用和Java应用等多个领域,每个领域都包含了丰富的实例和项目。这些源码都是基于各自平台的最新技术和标准编写,确保了在对应环境下能够无缝运行。同时,源码中配备了详细的注释和文档,帮助用户快速理解代码结构和实现逻辑。 适用人群: 这些源码资源特别适合大学生群体。无论你是计算机相关专业的学生,还是对其他领域编程感兴趣的学生,这些资源都能为你提供宝贵的学习和实践机会。通过学习和运行这些源码,你可以掌握各平台开发的基础知识,提升编程能力和项目实战经验。 使用场景及目标: 在学习阶段,你可以利用这些源码资源进行课程实践、课外项目或毕业设计。通过分析和运行源码,你将深入了解各平台开发的技术细节和最佳实践,逐步培养起自己的项目开发和问题解决能力。此外,在求职或创业过程中,具备跨平台开发能力的大学生将更具竞争力。 其他说明: 为了确保源码资源的可运行性和易用性,特别注意了以下几点:首先,每份源码都提供了详细的运行环境和依赖说明,确保用户能够轻松搭建起开发环境;其次,源码中的注释和文档都非常完善,方便用户快速上手和理解代码;最后,我会定期更新这些源码资源,以适应各平台技术的最新发展和市场需求。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值