CF1261F Xor-Set

将区间拆分为 ([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;
}
原文地址:https://www.cnblogs.com/lhm-/p/14461921.html