1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
| // 더 많은 정보는 42jerrykim.github.io 에서 확인하세요.
#include <bits/stdc++.h>
using namespace std;
using u64 = unsigned long long;
using i64 = long long;
static inline int floorLog2(u64 x) {
return 63 - __builtin_clzll(x);
}
static inline i64 blockMax(int k) {
if (k == 0) return 0; // block [0,0] -> J(0)=0
return 1LL + 1LL * k * (k + 1) / 2; // full block B_k = [2^k-1, 2^{k+1}-2]
}
static i64 Jvalue(u64 n) {
i64 res = 0;
while (n > 0) {
int k = floorLog2(n + 1);
res += k;
n -= ((1ULL << k) - 1);
}
return res;
}
static i64 prefixMax(u64 y); // forward
static i64 rangeMax(u64 x, u64 y); // forward
static i64 prefixMax(u64 y) {
if (y == 0) return 0;
int ky = floorLog2(y + 1);
u64 startKy = (1ULL << ky) - 1;
i64 A = (ky >= 2) ? (1LL + 1LL * (ky - 1) * ky / 2) : 0; // max over full blocks B_0..B_{ky-1}
i64 B = ky + prefixMax(y - startKy); // partial of B_ky
return max(A, B);
}
static i64 rangeMax(u64 x, u64 y) {
if (x == 0) return prefixMax(y);
if (x == y) return Jvalue(x);
int kx = floorLog2(x + 1);
u64 startX = (1ULL << kx) - 1;
u64 endX = (1ULL << (kx + 1)) - 2;
if (y <= endX) {
// same block
return kx + rangeMax(x - startX, y - startX);
}
// split: left partial, middle full blocks, right partial
i64 leftCandidate = kx + rangeMax(x - startX, (1ULL << kx) - 1);
int ky = floorLog2(y + 1);
i64 middleCandidate = (ky >= kx + 2) ? blockMax(ky - 1) : (i64)-4e18;
u64 startY = (1ULL << ky) - 1;
i64 rightCandidate = ky + prefixMax(y - startY);
return max(leftCandidate, max(middleCandidate, rightCandidate));
}
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int T;
if (!(cin >> T)) return 0;
while (T--) {
u64 x, y;
cin >> x >> y;
cout << rangeMax(x, y) << '\n';
}
return 0;
}
|