异或的常用性质

性质

1.

百度百科给的

最主要的性质就是归零和结合,其他的就都是拓展了。

例题:P1469

2.

\(a \bigoplus b<=a+b\)

关于这个不等式比较好的理解为异或就是不进位的加法

例题:luoguP5514

应用

异或哈希

异或跟hash一样,也是会发生冲突的

例如:$1 \bigoplus 2 = 5 \bigoplus 6 $

那我们要怎么去避免冲突呢,我们就可以借助hash的思想,对异或值做一个映射,或基于一个base来达成。

来看这道题,我们先来分析Crying的必胜策略:

假设Crying首先拿最小的数,如果最小的数有奇数个,那Crying会赢,如果为偶数个,那Crying肯定不会上来就拿最小的数,而是先去考虑拿第二小的数,那同样如果第二小的数为奇数个,Crying胜,如果为偶数个,那就接着考虑第三小的数,以此类推……

那转化一下题意就是求保证路径上每个数字不会出现偶数次的路径,再转化一下那这就是要保证路径的异或和不为 \(0\) (异或的归零性质,相同的数两两相抵消)。

但是,这样就会出现一个问题:异或冲突

我们就可以用上面的方法来避免这个问题,那这题就好办了,我们加边的时候给边权乘一个base,然后dfs跑一遍每个点到根节点的异或和,最后统计一下。这个时间限制不支持\(O(n^2)\)的操作,我们就可以开个map存一下dis相同的个数,最后减去即可。

点击查看代码
#include<bits/stdc++.h>
using namespace std;

#define int long long
const int N=5e6+107;
int n;

int read()
{
	int f=1,s=0;char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
	while(ch>='0'&&ch<='9'){s=(s<<1)+(s<<3)+(ch^48);ch=getchar();}
	return f*s;
}

unsigned long long qpow(unsigned long long a,int b)
{
	unsigned long long ans=1;
	while(b)
	{
		if(b&1) ans=ans*a;
		a=a*a;
		b=b>>1;
	}
	return ans;
}

int h[N],to[N],nxt[N],w[N],tot;
void add(int x,int y,int dt)
{
	to[++tot]=y;
	nxt[tot]=h[x];
	w[tot]=dt;
	h[x]=tot;
}
unordered_map<int,int>mp,vis;

int dis[N];
void dfs(int u,int fa)
{
	for(int i=h[u];i;i=nxt[i])
	{
		int v=to[i];
		if(v==fa) continue;
		dis[v]=dis[u]^w[i];
		dfs(v,u);
	}
	mp[dis[u]]++;
}

void clear()
{
	memset(h,0,sizeof h);
	mp.clear(); vis.clear();
	tot=0;
}

signed main()
{
	int T=read();
	while(T--)
	{
		clear();
		n=read();
		for(int i=1;i<=n-1;i++)
		{
			int x=read(),y=read(),dt=qpow(237,read()+1);
			add(x,y,dt); add(y,x,dt);
		}
		dfs(1,0);
		int ans=n*(n-1)/2;
		for(int i=1;i<=n;i++)
		{
			if(vis[dis[i]]) continue;
			ans-=mp[dis[i]]*(mp[dis[i]]-1)/2;
			vis[dis[i]]=1;
		}
		printf("%lld\n",ans);
	}
}
posted @ 2024-08-21 19:18  zhengchenxi  阅读(401)  评论(0)    收藏  举报