题解 CF1665E 【MinimizOR】
Analysis
线段树解法。
结论:
证明:采用数学归纳法。原命题
对于
对于
-
若当前最高位有
\ge 2 个0 ,根据高位贪心策略,当前位选0 ,最小值一定是k-1 位的最小值,一定在前k 小值中。 -
若当前为高位没有
0 ,则只能选一,结果是k-1 位中的最小值+2^{k-1} ,也一定在前k 小值中。 -
若当前位有
1 个0 ,当前位一定是1 ,找当前位为1 的最小值一定在前k 个当前位为1 的数中,加上一个当前位为0 的。因此一定在前k+1 小值中。
用线段树维护区间最小值,每次询问找到区间前
Code
Talk is cheap, show me the code.
Codeforces Status
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define mid (l+r)/2
#define For(i,j,k) for(int i=(j);i<=(k);i++)
#define Rof(i,j,k) for(int i=(j);i>=(k);i--)
pair<int,int> tr[400010];
void upd(int c,int l,int r,int x,int val){
if(l==r){
tr[c]=make_pair(val,x);
return;
}
if(x<=mid) upd(c*2,l,mid,x,val);
else upd(c*2+1,mid+1,r,x,val);
tr[c]=min(tr[c*2],tr[c*2+1]);
}
pair<int,int> qry(int c,int l,int r,int x,int y){
if(l==x&&r==y) return tr[c];
else if(y<=mid) return qry(c*2,l,mid,x,y);
else if(x>mid) return qry(c*2+1,mid+1,r,x,y);
else return min(qry(c*2,l,mid,x,mid),qry(c*2+1,mid+1,r,mid+1,y));
}
int n,q,a[100010];
vector<pair<int,int> > now;
void work(){
cin>>n;
For(i,1,n) cin>>a[i];
For(i,1,n) upd(1,1,n,i,a[i]);
cin>>q;
while(q--){
int l,r;cin>>l>>r;
now.clear();int lim=min(r-l+1,31ll);
For(i,1,lim) now.push_back(qry(1,1,n,l,r)),upd(1,1,n,now.back().second,(1ll<<31));
int mn=(1ll<<31);
For(i,0,now.size()-1) For(j,i+1,now.size()-1) mn=min(mn,now[i].first|now[j].first);
cout<<mn<<endl;
for(auto p:now) upd(1,1,n,p.second,a[p.second]);
}
}
signed main(){
ios::sync_with_stdio(false),cin.tie(0);
int T;cin>>T;
while(T--) work();
}