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]\)

posted @ 2024-06-21 17:52  Alric  阅读(4)  评论(0编辑  收藏  举报