一個不太複雜的做法。
首先我們可以考慮將每一段區間拆成 \(\log V\) 級別的形如 \([p,p+2^q)\) 個段,其實就是可以理解為一段字首加上一段自由段,然後我們考慮將 \(A,B\) 進行合併合併完之後的每一段也是長成剛剛那樣,但是這樣子合併我們得到的段有 \(\mathcal{O}(n^2\log^2V)\) 個級別的段,無法透過。
合併時我們產生了很多的空間浪費。觀察到在合併 \([p_A,p_A+2^{q_A})\) 和 \([p_B,p_B+2^{q_B})\) 兩段時,只有滿足 \(p_A=p_B\),或 \(\min(p_A,p_B)=0\) 時,這個合併才是有意義的,為什麼呢?
觀察拆段時的過程,每當我們在加入一個區間後,我們會改變一下當前的位並往後繼續加入新的區間,這提醒我們,在 \(q_A,q_B\) 都大於零的時候,\(\left|q_A-q_B\right|\ge1\) 時我們的合併是無意義的。因為我們顯然可以讓自由段更短的段繼續縮減自由段並與自由段較長的合併,所以這樣子我們得到的答案段數量級只有 \(\mathcal{O}(n^2\log V)\) 級別了。
但是我們最後還需要去重,觀察到這些段顯然要麼包含要麼不交,所以直接排序然後去重即可,常數不是很大就可以透過。
程式碼:
#include <bits/stdc++.h>
#define int long long
#define rep(i, l, r) for (int i = l; i <= r; ++ i)
#define rrp(i, l, r) for (int i = r; i >= l; -- i)
#define eb emplace_back
#define inf 1000000000
#define linf 100000000000000
#define pii pair <int, short>
using namespace std;
constexpr int N = 2e5 + 5, P = 998244353;
inline int rd ()
{
int x = 0, f = 1;
char ch = getchar ();
while (! isdigit (ch)) { if (ch == '-') f = -1; ch = getchar (); }
while (isdigit (ch)) { x = (x << 1) + (x << 3) + ch - 48; ch = getchar (); }
return x * f;
}
int n, m;
vector <pii> v1, v2, v3;
signed main ()
{
// freopen ("1.in", "r", stdin);
// freopen ("1.out", "w", stdout);
n = rd ();
rep (t, 1, n)
{
int l = rd (), r = rd ();
if (l == r)
{
v1.eb (pii (l, 0));
continue;
}
int x = 0, d;
rrp (j, 0, 60)
{
int bl = l >> j & 1, br = r >> j & 1;
if (bl == br) d = j;
else break;
x |= bl; x <<= 1;
}
int y = x;
y |= 1; y <<= 1;
rrp (j, 0, d - 2)
{
int b = r >> j & 1;
if (b) v1.eb (pii (y, j));
y |= b; y <<= 1;
}
v1.eb (pii (y >> 1, 0));
y = x; y <<= 1;
rrp (j, 0, d - 2)
{
int a = l >> j & 1;
if (! a) v1.eb (pii (y | 1, j));
y |= a; y <<= 1;
}
v1.eb (pii (y >> 1, 0));
}
m = rd ();
rep (t, 1, m)
{
int l = rd (), r = rd ();
if (l == r)
{
v2.eb (pii (l, 0));
continue;
}
int x = 0, d;
rrp (j, 0, 60)
{
int bl = l >> j & 1, br = r >> j & 1;
if (bl == br) d = j;
else break;
x |= bl; x <<= 1;
}
int y = x;
y |= 1; y <<= 1;
rrp (j, 0, d - 2)
{
int b = r >> j & 1;
if (b) v2.eb (pii (y, j));
y |= b; y <<= 1;
}
v2.eb (pii (y >> 1, 0));
y = x; y <<= 1;
rrp (j, 0, d - 2)
{
int a = l >> j & 1;
if (! a) v2.eb (pii (y | 1, j));
y |= a; y <<= 1;
}
v2.eb (pii (y >> 1, 0));
}
for (auto u : v1)
{
for (auto v : v2)
{
int x = u.first, y = u.second, xx = v.first, yy = v.second;
if (y > yy) swap (y, yy), swap (x, xx);
if (! y || yy == y)
{
int g = ((x << y) ^ (xx << yy)) >> yy << yy;
v3.eb (pii (g, - yy));
}
}
}
sort (v3.begin (), v3.end ());
int ans = 0, cnt = 0;
int w = -1;
for (int i = 0; i < v3.size (); ++ i)
{
int p = v3[i].first, q = - v3[i].second;
if (w >= p) continue;
w = p + (1ll << q) - 1; ++ cnt;
int x = 1ll << q;
(ans += x % P * (p % P) % P + ((x >> 1) % P) * ((x - 1) % P) % P) %= P;
}
printf ("%lld\n", ans);
}
/*
*/