YbtOJ#20075区间异或

Posted stoorz

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了YbtOJ#20075区间异或相关的知识,希望对你有一定的参考价值。

题目

题目链接:http://noip.ybtoj.com.cn/problem/20075
技术图片

思路

先做一遍前缀异或和,然后问题转化为序列中任选两个数异或起来不小于 (k)
从高位到低位建立 Trie 树,分 (01) 计算答案即可。
时间复杂度 (O(Tnlog 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
",ans);
	}
	return 0;
}



以上是关于YbtOJ#20075区间异或的主要内容,如果未能解决你的问题,请参考以下文章

ybtoj树状数组差分例题4区间修改区间查询

ybtoj线段树课堂过关例题1求区间和

luoguP3374ybtoj树状数组例题1单点修改区间查询

luogu P4514ybtoj树状数组课堂过关差分 例题6区间修改区间查询 & 上帝造题的七分钟

luogu P3372ybtoj线段树课堂过关例题2区间查改 &模板线段树 1

luogu P4170ybtoj 区间DP课堂过关 例题2木板涂色 & [CQOI2007]涂色