CF1878E

发布时间 2023-10-02 20:57:35作者: The_cosmos

\(Solution\)

比较典的题。

我们知道与运算的一个性质:对于任意自然数 \(x, y\) 都有 \(x\&y\leq\max(x,y)\),读者可以自行证明,过程并不繁琐。

那么对于一段区间 \([l,r]\),当 \(l\) 固定,\(r\) 不断变大时,\(f(l,r)\) 会呈单调不上升的趋势。

这就满足了二分的单调性。此时整个算法的复杂度在 \(\Theta(Tq\log n)\) 级别,而最后的步骤就是求 \(f(l,r)\)

所以我们的问题变成了如何在 \(\Theta(\log n)\) 时间范围内求 \(f(l,r)\),这是时限内能满足的最大时间。

这是典型的区间问题,很自然的想到 ST 表或是线段树。

那么问题得解。最终时间复杂度 \(\Theta(Tq\log^2 n)\)

\(Code\)

#define int long long
const int N = 1e6 + 5;
namespace Jelly {
	int n, q;
	int tree[N << 2], a[N];
	void Build(int x, int l, int r) {
		if(l == r) {
			tree[x] = a[l];
			return ;
		}
		int mid = l + r >> 1;
		Build(x << 1, l, mid);
		Build(x << 1 | 1, mid + 1, r);
		tree[x] = tree[x << 1] & tree[x << 1 | 1];
	}
	int Query(int l, int r, int x, int L, int R) {
		if(r < L || l > R) return INT_MAX;
		if(L <= l && r <= R) return tree[x];
		int mid = l + r >> 1;
		return Query(l, mid, x << 1, L, R) & Query(mid + 1, r, x << 1 | 1, L, R);
	}
	int main() {
		Read(n);
		for(int i = 1; i <= n; i ++) Read(a[i]);
		Build(1, 1, n);
		Read(q);
		while(q --) {
			int lft, k;
			Read(lft, k);
			int l = lft, r = n;
			if(a[lft] < k) {
				Write(-1, ' ');
				continue;
			}
			while(l < r) {
				int mid = l + r + 1 >> 1;
				if(Query(1, n, 1, lft, mid) >= k) l = mid;
				else r = mid - 1;
			}
			Write(l, ' ');
		}
		Writeln();
		return 0;
	}
}
signed main() {
	int T = 1;
	Read(T);
	while(T --) Jelly::main();
	return 0;
}