hdu 6730 线段树 2019-ccpc网络赛02

hdu 6730 线段树 2019-ccpc网络赛02

题意:

数组a时一个1~n的全排列,有如下两种操作
1 x,将a[x]+=1e7
2 r,k 查询大于等于k的最小值但不在数组中前r项中
(数组长度1e5,k<1e5)

思路:

首先观察可知在题目中查询的答案一定再1~n+1的范围内(因为k很小,操作一加的很大)
那么其实1操作就是取消掉禁用。之后考虑正着做比较难,则反着做查询k~n+1中最小的没被禁用的。
这里用一颗线段树就表示num[i]是否被禁用,查询的时候查询k~n+1中最小的没被ban掉的就好了,这里左右子树选择的时候再判断一下左子树上k~mid的最值就好。左右判断一个log,查询本身一个log。最终nlogn^2通过此题.

代码:

#include <bits/stdc++.h>
#define LL long long
#define pii pair<int,int>
#define PB push_back
#define X first
#define Y second
using namespace std;
int t,n,m,x;
const int maxn = 5e5;
const int inf = 0x3f3f3f3f;
int a[maxn],b[maxn];
int rmin[maxn];
int ans,op,pos,minx,k,r;
void init(){
    memset(rmin,0,sizeof(rmin));
}
void update(int x,int y,int L,int R,int rt){
    if(L==R){
        rmin[rt]=y;
        return;
    }
    int mid = (L+R)/2;
    if(x<=mid) update(x,y,L,mid,rt*2);
    else update(x,y,mid+1,R,rt*2+1);
    rmin[rt]=max(rmin[rt*2],rmin[rt*2+1]);
}
int get_min(int L,int R,int l,int r,int rt){
    if(L>=l&&R<=r) return rmin[rt];
    if(r<L||l>R) return 0;
    int mid = (L+R)/2;
    return max(get_min(L,mid,l,r,rt*2),get_min(mid+1,R,l,r,rt*2+1));
}
void query(int L,int R,int r,int k,int rt){
    if(L==R){
        ans = L;
        return;
    }
    int mid = (L+R)/2;
    if(k<=mid&&rmin[rt*2]>r&&get_min(L,mid,k,mid,rt*2)>r) query(L,mid,r,k,rt*2);
    else query(mid+1,R,r,k,rt*2+1);
}
int main(){
    //cin>>t;
    scanf("%d",&t);
    while(t--){
        //cin>>n>>m;
        scanf("%d%d",&n,&m);
        init();
        ans=0;
        for(int i=1;i<=n;i++){
            //cin>>x;
            scanf("%d",&x);
            a[x]=i;
            b[i]=x;
            update(x,i,1,n+1,1);
        }
        update(n+1,inf,1,n+1,1);
        for(int i=0;i<m;i++){
            scanf("%d",&op);
            //cin>>op;
            if(op==1){
                scanf("%d",&pos);
                //cin>>pos;
                pos^=ans;
                update(b[pos],inf,1,n+1,1);
            }
            else{
                scanf("%d%d",&r,&k);
                //cin>>r>>k;
                r^=ans;k^=ans;
                //cout<<"r:"<<r<<" k:"<<k<<endl;
                ans = minx = inf;
                query(1,n+1,r,k,1);
                printf("%d\n",ans);
                //cout<<ans<<endl;
            }
        }
    }
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/zhangxianlong/p/11432003.html
今日推荐