ST表
例题:Iva & Pav
题目大意:给定序列\(a_1,..,a_n\)和多个形如l k
的询问。对于每个询问求出最大的 \(r\) 使得 \(a_l\And a_{l+1}\& \dots\& a_{r-1}\&a_r\ge k\)。
步骤一:预处理出对于\(1\le i \le n\)的所有\(\lfloor log_2(i)\rfloor\)的值。
for(ll i=2;i<=200000;i++)lg[i]=lg[i>>1]+1;
步骤二:将原数列赋值给ST表
for(ll i=1;i<=n;i++)st[i][0]=a[i];
步骤三:构建ST表
for(ll j=1;j<=lg[n];j++)
for(ll i=1;i+(1<<j)-1<=n;i++)
st[i][j]=st[i][j-1]&st[i+(1<<(j-1))][j-1];
步骤四:询问区间信息
ll qst(ll l,ll r){return st[l][lg[r-l+1]]&st[r-(1<<lg[r-l+1])+1][lg[r-l+1]];}
完整代码:
#include<bits/stdc++.h>
#define pt printf(">>>")
#define mid (((l)+(r))/2)
#define sq(x) ((x)*(x))
#define cu(x) ((x)*(x)*(x))
using namespace std;
typedef long long ll;
typedef long double ld;
const ll N=2e5+10,inf=1e18+10,mod=1000000007;
ll n,a[N],lg[N],st[N][25];
ll qst(ll l,ll r){return st[l][lg[r-l+1]]&st[r-(1<<lg[r-l+1])+1][lg[r-l+1]];}
int main(){
ios::sync_with_stdio(0);
cin.tie(0),cout.tie(0);
for(ll i=2;i<=200000;i++)lg[i]=lg[i>>1]+1;
int T=1;
cin >> T;
while(T--){
cin >> n;
for(ll i=1;i<=n;i++)cin >> a[i],st[i][0]=a[i];
for(ll j=1;j<=lg[n];j++)
for(ll i=1;i+(1<<j)-1<=n;i++)
st[i][j]=st[i][j-1]&st[i+(1<<(j-1))][j-1];
ll q;
cin >> q;
while(q--){
ll p,k;
cin >> p >> k;
ll l=p,r=n,ret=-1;
while(l<=r){
if(qst(p,mid)>=k)ret=mid,l=mid+1;
else r=mid-1;
}
cout << ret << ' ';
}
cout << endl;
}
return 0;
}
ST数组大小:
数量级\(10^6\)以内时,开\(st[N][25]\);
数量级\(10^8\)以内时,开\(st[N][30]\)。
更准确地说,是开\(st[N][\lfloor log_{2}N\rfloor+1]\)