zoukankan      html  css  js  c++  java
  • hdu6703 线段树+set

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6703

    给你一个数组两种操作。操作一是将pos位置的数字加上10000000;操作二是给你个r和k,问你最小的不小于k且没在数组a的[1,r]这个区间内出现过,并输出这个数。(pos,r,k均需异或上一次的答案,初始答案为零)。

    因为k不大于n所以如果某个位置的数进行了操作一那么就代表下一次的操作二选出来的数可能是这个数。

    我们用线段树维护最大的位置,线段树的节点表示值,节点存的是这个值在数组a中的位置。每次进行操作二时,我们查询线段树区间[k,n]内大于r的最小值。

    因为如果进行了操作一后,线段树找出的值不一定就是最小的了,所以我们还要从所有进行了操作一的数中找出最小的且大于等于k的数,答案就是这两个数中最小的数。

    #include<iostream>
    #include<algorithm>
    #include<set>
    using namespace std;
    #define ls l,mid,rt<<1
    #define rs mid+1,r,rt<<1|1
    #define maxn 100005
    int maxx[maxn<<2],a[maxn],b[maxn],v[maxn];
    int t,n,m;
    inline void pushup(int rt)
    {
        maxx[rt]=max(maxx[rt<<1],maxx[rt<<1|1]);
    }
    inline void build(int l,int r,int rt)
    {
        if(l==r)
        {
            maxx[rt]=b[l];
            return ;
        }
        int mid=l+r>>1;
        build(ls);build(rs);
        pushup(rt);
    }
    inline int fid(int k,int l,int r,int rt)//返回的是在不考虑操作一下符合的最小值 
    {
        if(l==r)
        {
            if(maxx[rt]>=k)return l;
            else return n+1;
        }
        int mid=l+r>>1;
        int ret=n+1;
        //如果左儿子的最大值大于k,那么就往左区间找,因为这代表值在[l,mid]内的数有出现数组a的第r个之后的(r是题目给的r) 
        if(maxx[rt<<1]>=k)ret=min(ret,fid(k,ls));
        //如果右儿子的最大值大于k,那么就往右区间找 
        else if(maxx[rt<<1|1]>=k)ret=min(ret,fid(k,rs));
        return ret;
    }
    inline int query(int L,int R,int k,int l,int r,int rt)
    {
        if(L<=l&&R>=r)
        {
            return fid(k,l,r,rt);
        }
        int mid=l+r>>1;
        int ret=n+1; 
        if(L<=mid)ret=min(ret,query(L,R,k,ls));
        if(R>mid)ret=min(ret,query(L,R,k,rs));
        return ret;
    }
    int main()
    {
        scanf("%d",&t);
        while(t--)
        {
            scanf("%d%d",&n,&m);
            for(int i=1;i<=n;i++)
            {
                scanf("%d",&a[i]);
                b[a[i]]=i;
                v[i]=0;
            }
            build(1,n,1);
            int op,ans=0;
            set<int>s;
            set<int>::iterator it; 
            while(m--)
            {
                scanf("%d",&op);
                if(op==1)
                {
                    int pos;
                    scanf("%d",&pos);
                    pos^=ans;
                    if(!v[pos])
                    {
                        s.insert(a[pos]);
                        v[pos]=1;
                    }
                }
                else
                {
                    int r,k;
                    scanf("%d%d",&r,&k);
                    r^=ans;k^=ans;
                    ans=n+1;//答案最大即为n+1 
                    if(r!=n)
                    {
                        ans=query(k,n,r+1,1,n,1);//查询区间[k,n]内大于r+1的最小的数 
                    }
                    it=s.lower_bound(k);//从进行了操作一的数中找到符合条件的最小值 
                    if(it!=s.end())
                    {
                        ans=min(ans,(*it));//取最小的一个 
                    }
                    printf("%d
    ",ans);
                }
            }
        }
        return 0;
    }
  • 相关阅读:
    转】使用Maven编译项目遇到——“maven编码gbk的不可映射字符”解决办法
    转】Maven学习总结(九)——使用Nexus搭建Maven私服
    转】Maven学习总结(八)——使用Maven构建多模块项目
    转】Maven学习总结(七)——eclipse中使用Maven创建Web项目
    转】Maven学习总结(六)——Maven与Eclipse整合
    Storm具体解释一、Storm 概述
    ThinkPHP 连接Oracle的配置写法,(使用Oci扩展而非PDO的写法)
    VBA怎样统计同一类型的数据的总和
    在html中禁用自己主动完毕
    Sort方法的扩展
  • 原文地址:https://www.cnblogs.com/chen99/p/11430072.html
Copyright © 2011-2022 走看看