1 条题解

  • 0
    @ 2024-3-15 19:33:29

    考虑建线段树维护整个 bb 序列,在每个结点处维护答案。如何合并两个结点?若子区间在同一个子结点直接更新答案,否则子区间跨越中点。

    考虑在每个结点处维护最靠左的第 kk 位(二进制)是 11 的数、最靠右的第 kk 位是 11 的数(0k<300 \leq k < 30)。

    合并时从高位到低位考虑:

    • 若这一位上 vv11,则左侧最靠右的 11 和右侧最靠左的 11 必须选一个。贪心选择得到的新区间的 aa 的最大值小的那个,如果相同,就贪心地都选(这样考虑低位的时候 11 尽可能多)。
    • 若这一位上 vv00
      • 若仍然选择一个 11,则无需考虑低位结果已经至少为 vv,直接更新到答案里去即可。
      • 若不选择 11,接着考虑下一位即可。

    修改操作直接在线段树上修改即可。时间复杂度 Θ((n+q)lognlogmaxbi)\Theta((n+q)\log n\log\max b_i)

    #include<bits/stdc++.h>
    using namespace std;
    const int INF=2e9;
    
    int n,q,v,a[200001],b[200001];
    
    int maxn[200001][19],lg[200001];
    inline int queryMax(int l,int r){
        int k=lg[r-l+1];
        return max(maxn[l][k],maxn[r-(1<<k)+1][k]);
    }
    
    struct SegmentTree{
        struct Node{
            int l,r;
            int answer,lpos[30],rpos[30];
            inline void update(int val){
                for(int k=29;k>=0;k--){
                    lpos[k]=((val>>k)&1)?l:n+1;
                    rpos[k]=((val>>k)&1)?r:0;
                }
                answer=val>=v?a[l]:INF;
            }
        }node[800001];
    
        inline friend Node operator+(Node lc,Node rc){
            Node result;
            result.l=lc.l,result.r=rc.r;
            result.answer=min(lc.answer,rc.answer);
            for(int i=0;i<30;i++){
                result.lpos[i]=min(lc.lpos[i],rc.lpos[i]);
                result.rpos[i]=max(lc.rpos[i],rc.rpos[i]);
            }
            int l=lc.r,r=rc.l;
            bool flag=true;
            for(int i=29;i>=0;i--){
                if((v>>i)&1){
                    if(lc.rpos[i]<result.l&&rc.lpos[i]>result.r){flag=false; break;}
                    if(lc.rpos[i]<result.l){r=max(r,rc.lpos[i]);continue;}
                    if(rc.lpos[i]>result.r){l=min(l,lc.rpos[i]);continue;}
                    int lres=queryMax(l,max(r,rc.lpos[i]));
                    int rres=queryMax(min(lc.rpos[i],l),r);
                    if(lres==rres)l=min(l,lc.rpos[i]),r=max(r,rc.lpos[i]);
                    else if(lres<rres)r=max(r,rc.lpos[i]);
                    else l=min(l,lc.rpos[i]);
                }
                else{
                    if(lc.rpos[i]>=result.l)result.answer=min(result.answer,queryMax(min(l,lc.rpos[i]),r));
                    if(rc.lpos[i]<=result.r)result.answer=min(result.answer,queryMax(l,max(r,rc.lpos[i])));
                }
            }
            if(flag)result.answer=min(result.answer,queryMax(l,r));
            return result;
        }
    
        inline void pushup(int id){
            node[id]=node[id<<1]+node[id<<1|1];
        }
    
        void build(int id,int l,int r){
            node[id].l=l,node[id].r=r;
            if(l==r){
                node[id].update(b[l]);
                return;
            }
            int mid=l+r>>1;
            build(id<<1,l,mid);
            build(id<<1|1,mid+1,r);
            pushup(id);
        }
    
        void updateOne(int id,int pos,int val){
            if(node[id].l==node[id].r){
                node[id].update(val);
                return;
            }
            int mid=node[id].l+node[id].r>>1;
            if(pos<=mid)updateOne(id<<1,pos,val);
            else updateOne(id<<1|1,pos,val);
            pushup(id);
        }
    
        Node query(int id,int l,int r){
            if(l<=node[id].l&&node[id].r<=r)
                return node[id];
            int mid=node[id].l+node[id].r>>1;
            if(r<=mid)return query(id<<1,l,r);
            if(mid<l)return query(id<<1|1,l,r);
            return query(id<<1,l,r)+query(id<<1|1,l,r);
        }
    }_;
    
    int main(){
        lg[0]=-1;
        for(int i=1;i<=200000;i++)
            lg[i]=lg[i>>1]+1;
        int T; scanf("%d",&T);
        while(T--){
            scanf("%d%d",&n,&v);
            for(int i=1;i<=n;i++)
                scanf("%d",a+i),maxn[i][0]=a[i];
            for(int k=1;k<=18;k++)
                for(int i=1;i+(1<<k)-1<=n;i++)
                    maxn[i][k]=max(maxn[i][k-1],maxn[i+(1<<k-1)][k-1]);
            for(int i=1;i<=n;i++)
                scanf("%d",b+i);
            _.build(1,1,n);
            scanf("%d",&q);
            while(q--){
                int op,x,y;
                scanf("%d%d%d",&op,&x,&y);
                if(op==1)_.updateOne(1,x,y);
                else{
                    int answer=_.query(1,x,y).answer;
                    if(answer==INF)answer=-1;
                    printf("%d ",answer);
                }
            }
            printf("\n");
        }
        return 0;
    }
    
    • 1

    信息

    ID
    9417
    时间
    5000ms
    内存
    1024MiB
    难度
    10
    标签
    递交数
    2
    已通过
    1
    上传者