【YbtOJ#20075】区间异或

题目

题目链接:http://noip.ybtoj.com.cn/problem/20075

思路

先做一遍前缀异或和,然后问题转化为序列中任选两个数异或起来不小于 \(k\)
从高位到低位建立 Trie 树,分 \(01\) 计算答案即可。
时间复杂度 \(O(Tn\log n)\)

代码

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;

const int N=1000010,LG=30;
int Q,n,m;
ll ans;

int read()
{
	int d=0; char ch=getchar();
	while (!isdigit(ch)) ch=getchar();
	while (isdigit(ch)) d=(d<<3)+(d<<1)+ch-48,ch=getchar();
	return d;
}

struct Trie
{
	int tot,c[N*LG][2],size[N*LG];
	
	void ins(int v)
	{
		int p=1;
		for (int i=LG;i>=0;i--)
		{
			int id=(v>>i)&1;
			if (!c[p][id]) c[p][id]=++tot;
			p=c[p][id];
			size[p]++;
		}
	}
	
	int query(int v)
	{
		int p=1,sum=0;
		for (int i=LG;i>=0;i--)
		{
			int id=(v>>i)&1,id1=(m>>i)&1;
			if (!id1) sum+=size[c[p][id^1]];
			p=c[p][id^id1];
		}
		return sum+size[p];
	}
	
	void clr(int p)
	{
		if (c[p][0]) clr(c[p][0]);
		if (c[p][1]) clr(c[p][1]);
		size[p]=c[p][0]=c[p][1]=0;
	}
}trie;

void prework()
{
	ans=0; trie.tot=1;
	trie.clr(1);
	trie.ins(0);
}

int main()
{
	freopen("xor.in","r",stdin);
	freopen("xor.out","w",stdout);
	Q=read();
	while (Q--)
	{
		prework();
		n=read(); m=read();
		for (int i=1,x=0;i<=n;i++)
		{
			x^=read();
			ans+=trie.query(x);
			trie.ins(x);
		}
		printf("%lld\n",ans);
	}
	return 0;
}
posted @ 2020-11-02 15:16  stoorz  阅读(80)  评论(0编辑  收藏  举报