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里的数是可以用的。要和1~r的数都不相同,那么我们用主席树查找区间l+1~n+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
#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< 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<::iterator it=s.lower_bound(y);
                int t=inf;
                if(it!=s.end())
                    t=*it;
                //             cout<<"t"<

你可能感兴趣的:(2019CCPC网络选拔赛 hdu6703 array(主席树+set))