zoukankan      html  css  js  c++  java
  • HDU-6703 array (线段树)

    题意

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

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

    数据范围:

    (1le nle 100000,1le mle 100000,1le rle n,1le kle 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就可以了, 这样对于(kle 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
    ",res);
                }
            }
        }
        return 0;
    }
    
  • 相关阅读:
    java关键字synchronized
    JVM调优之jstack找出最耗cpu的线程并定位代码
    高性能Mysql
    awk使用入门
    JVM性能调优监控工具
    java垃圾回收算法
    JVM内存模型
    jvm之内存分配与回收策略
    leetcode 78. 子集(c++)
    leetcode 148. 排序链表(c++)
  • 原文地址:https://www.cnblogs.com/1625--H/p/11404011.html
Copyright © 2011-2022 走看看