1 条题解
-
0
考虑建线段树维护整个 序列,在每个结点处维护答案。如何合并两个结点?若子区间在同一个子结点直接更新答案,否则子区间跨越中点。
考虑在每个结点处维护最靠左的第 位(二进制)是 的数、最靠右的第 位是 的数()。
合并时从高位到低位考虑:
- 若这一位上 是 ,则左侧最靠右的 和右侧最靠左的 必须选一个。贪心选择得到的新区间的 的最大值小的那个,如果相同,就贪心地都选(这样考虑低位的时候 尽可能多)。
- 若这一位上 是 :
- 若仍然选择一个 ,则无需考虑低位结果已经至少为 ,直接更新到答案里去即可。
- 若不选择 ,接着考虑下一位即可。
修改操作直接在线段树上修改即可。时间复杂度 。
#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
- 上传者