zoukankan      html  css  js  c++  java
  • 2019CCPC网络选拔赛 hdu6703 array(主席树+set)

    题意

    给你一个1~n的排列,由两种操作:

    1 pos:将a[pos]+10 000 000

    2 r k:求大于等于k且不等于a[1~r]的数的最小值。

    强制在线。

    思路

    如果没有1操作,那么我们直接主席树就OK了。

    考虑不真正的进行修改,每次1操作就把a[pos]插进set,因为加10 000 000后肯定是大于n的,而k是小于等于n的,所以set里的数是可以用的。要和1r的数都不相同,那么我们用主席树查找区间r+1n+1的大于等于k的最小值即可,为什么是n+1呢,因为k<=n,如果k==n,那么满足条件且最小的数必定是n+1了。修改后的数的值变大了,而k<=n,显然这个修改后的值是对答案无影响的,但原来的值仍然是可以利用的,所以我们可以在set里二分查找第一个大于等于k的数,然后和主席树查到的取个最小值即可。

    至于主席树查询的技巧:要剪枝,当sum[v]-sum[u]<=0时,表示这个区间不存在大于等于k的数,直接return inf;先判断是否k<=mid,才能往区间左边走,如果找到满足条件的数了我们就不必再往区间右边找了,因为右边的数肯定比左边大,相当于减了一半的时间。

    代码

    #include<bits/stdc++.h>
    #define mid (l+r)/2
    using namespace std;
    
    const int N = 1e5+5;
    int n, q, sz, num = 0;
    int a[N], b[N], T[N];
    int sum[N<<5], L[N<<5], R[N<<5],mi[N<<5];
    #define inf 0x3f3f3f3f
    inline int build(int l, int r)
    {
        int rt = ++ num;
        sum[rt] = 0;
        if (l < r)
        {
            L[rt] = build(l, mid);
            R[rt] = build(mid+1, r);
        }
        return rt;
    }
    
    inline int update(int pre, int l, int r, int x)
    {
        int rt = ++ num;
        L[rt] = L[pre];
        R[rt] = R[pre];
        sum[rt] = sum[pre]+1;
        if (l < r)
        {
            if (x <= mid) L[rt] = update(L[pre], l, mid, x);
            else R[rt] = update(R[pre], mid+1, r, x);
        }
        return rt;
    }
    
    inline int query(int u, int v, int l, int r, int k)
    {
        if(sum[v]-sum[u]<=0)
            return inf;
        if(l==r)
            return l;
        int ans=inf;
        if(k<=mid)
            ans=min(ans,query(L[u], L[v], l, mid, k));
        if(ans==inf)
            ans=min(ans,query(R[u], R[v], mid+1, r, k));
        //  cout<<ans<<endl;
        return ans;
    }
    set<int> s;
    int main()
    {
        int TT;
        scanf("%d",&TT);
        while(TT--)
        {
            s.clear();
            scanf("%d%d", &n, &q);
            num=0;
            T[0] = build(1, n+1);
            for (int i = 1; i <= n; i ++)
            {
                scanf("%d", &a[i]);
                T[i] = update(T[i-1], 1, n+1, a[i]);
            }
            T[n+1]=update(T[n],1,n+1,n+1);
            int ans=0;
            while (q --)
            {
                int o,x,y;
                scanf("%d", &o);
                if(o==1)
                {
                    scanf("%d",&x);
                    x^=ans;
                    s.insert(a[x]);
                    //   ans=0;
                }
                else
                {
                    scanf("%d%d",&x,&y);
                    x^=ans,y^=ans;
                    //        cout<<x<<" "<<y<<endl;
                    set<int>::iterator it=s.lower_bound(y);
                    int t=inf;
                    if(it!=s.end())
                        t=*it;
                    //             cout<<"t"<<t<<endl;
                    ans=min(query(T[x],T[n+1],1,n+1,y),t);
                    printf("%d
    ",ans);
                }
            }
    
        }
        return 0;
    }
    
    
  • 相关阅读:
    Ubuntu Java环境变量配置
    Ubuntu 获得超级用户权限
    ubuntu 修改主机名
    NGSQC toolkit
    MySQL 常用命令
    Yii的事件和行为的区别和应用
    YII使用PHPExcel导入Excel文件的方法
    Yii: 扩展CGridView增加导出CSV功能
    YII中使用SOAP一定要注意的一些东西
    Yii 多表关联relations
  • 原文地址:https://www.cnblogs.com/mcq1999/p/11436115.html
Copyright © 2011-2022 走看看