将区间拆分为 ([x2^i,(x+1)2^i)) 的形式,发现两个区间中的数两两异或后形成的仍为一个区间,将 (A,B) 都拆分后区间两两异或会得到 (O(n^2log^2n)) 个区间,取并即为答案,但复杂度无法接受。
发现对于两个区间 ([x2^i,(x+1)2^i),[y2^j,(y+1)2^j),i>j),其异或后得到的结果仍是高位固定,后 (i) 位任意取,也就是第二个区间中有一段是不用考虑的,这是因为这一段在第一个区间中是任意取的。在线段树上就是只用考虑同一深度的区间,这样得到的区间个数就为 (O(n^2log n)) 了。
就用线段树来实现即可,(dfs) 的过程中记录当前高位的异或值,当有区间被完全覆盖后就返回。
#include<bits/stdc++.h>
#define maxn 100010
#define maxm 62
#define p 998244353
#define inv2 499122177
#define mid ((l+r)>>1)
#define mk make_pair
using namespace std;
typedef long long ll;
template<typename T> inline void read(T &x)
{
x=0;char c=getchar();bool flag=false;
while(!isdigit(c)){if(c=='-')flag=true;c=getchar();}
while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
if(flag)x=-x;
}
int n;
vector<pair<int,int> > ve[maxm];
struct node
{
int root,tot;
int ch[maxn][2];
bool tag[maxn];
void insert(ll L,ll R,ll l,ll r,int &x)
{
if(!x) x=++tot;
if(L<=l&&R>=r)
{
tag[x]=true;
return;
}
if(L<=mid) insert(L,R,l,mid,ch[x][0]);
if(R>mid) insert(L,R,mid+1,r,ch[x][1]);
}
}A,B;
ll dfs(int d,ll v)
{
for(int i=0;i<ve[d].size();++i)
{
pair<int,int> t=ve[d][i];
if(A.tag[t.first]||B.tag[t.second])
return (v+((((ll)1<<d)-1)%p)*inv2%p)%p*(((ll)1<<d)%p)%p;
}
ll val=0;
for(int x=0;x<=1;++x)
{
ve[d-1].clear();
for(int i=0;i<ve[d].size();++i)
{
pair<int,int> t=ve[d][i];
for(int y=0;y<=1;++y)
if(A.ch[t.first][y]&&B.ch[t.second][x^y])
ve[d-1].push_back(mk(A.ch[t.first][y],B.ch[t.second][x^y]));
}
if(ve[d-1].size()) val=(val+dfs(d-1,v|((ll)x<<(d-1))))%p;
}
return val;
}
int main()
{
read(n);
for(int i=1;i<=n;++i)
{
ll l,r;
read(l),read(r);
A.insert(l,r,0,((ll)1<<60)-1,A.root);
}
read(n);
for(int i=1;i<=n;++i)
{
ll l,r;
read(l),read(r);
B.insert(l,r,0,((ll)1<<60)-1,B.root);
}
ve[60].push_back(mk(A.root,B.root)),printf("%lld",dfs(60,0));
return 0;
}