牛客网 Xor Path(树,思维,dfs ,异或)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/wwwlps/article/details/88541114

链接:https://ac.nowcoder.com/acm/contest/272/B
来源:牛客网
 

时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 262144K,其他语言524288K
64bit IO Format: %lld

题目描述

给定一棵n个点的树,每个点有权值AiAi。定义path(i,j)path(i,j)表示 ii 到 jj 的最短路径上,所有点的点权异或和。

对于i=1∼n−1, j=i+1∼ni=1∼n−1, j=i+1∼n,求所有path(i,j)path(i,j)的异或和。

输入描述:

 

第一行一个整数n。

接下来n-1行,每行2个整数u,v,表示u,v之间有一条边。

第n+1行有n个整数,表示每个点的权值AiAi。

输出描述:

输出一个整数,表示所有path(i,j)path(i,j)的异或和,其中i=1∼n−1, j=i+1∼ni=1∼n−1, j=i+1∼n。

示例1

输入

复制

4
1 2
1 3
1 4
1 2 3 4

输出

复制

5

说明

 

path(1,2)=A1 xor A2=3path(1,3)=A1 xor A3=2path(1,4)=A1 xor A4=5path(2,3)=A2 xor A1 xor A3=0path(2,4)=A2 xor A1 xor A4=7path(3,4)=A3 xor A1 xor A4=6path(1,2)=A1 xor A2=3path(1,3)=A1 xor A3=2path(1,4)=A1 xor A4=5path(2,3)=A2 xor A1 xor A3=0path(2,4)=A2 xor A1 xor A4=7path(3,4)=A3 xor A1 xor A4=6

再将这6个数异或起来就可以得到答案5了。

备注:

1≤n≤5×105,0≤Ai≤1091≤n≤5×105,0≤Ai≤109。

题解:首先,这是一棵树,涉及异或,应该想到很多节点值会被异或多次,其中,同一个值异或偶数次的话,其贡献就为0,奇数次的话,只需要ans和其异或一下,那么问题来了,如何知道每一个节点值会被重复用到多次呢?

这里,我们可以对所有点单独考虑:

  1. 对某一个节点而言,它需要和除它以外的所有点连接,即n-1次
  2. 对某一个节点而言,它的子树之间可以相互连接
  3. 对某一个节点而言,它的所有子树节点可以通过该点和其它点连接

最终,问题可以转化为求所有节点的子树节点数目,时间复杂度应该是O(n)的,采用dfs,遍历一遍,详见代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<vector>
#include<map>
#include<set>
#include<algorithm>
#include<queue>
#include<stack>
#define LL long long
#define INF 0x3f3f3f3f
#define PI 3.1415926535897932384
using namespace std;
const int maxn=1000005;
LL n;
LL val[maxn],head[maxn],cnt;
LL ans;
LL sum[maxn];//用来记录一个节点下的所有节点数量 
bool book[maxn];
struct node
{
	LL u,v,nxt;
}edge[maxn];
void init()
{
	for(int i=0;i<maxn;i++)
	{
		head[i]=-1;
		sum[i]=1;
	}
	cnt=0;ans=0;
	memset(book,false,sizeof(book));
}
void addedge(int u,int v)
{
	edge[cnt].u=u;
	edge[cnt].v=v;
	edge[cnt].nxt=head[u];
	head[u]=cnt++;
}
void dfs(int rt)
{
	LL num=0;
	for(int i=head[rt];i!=-1;i=edge[i].nxt)
	{
		int v=edge[i].v;
		if(book[v]==true)
			continue;
		book[v]=true;
		dfs(v);
		num+=(sum[rt]-1)*sum[v];
		sum[rt]+=sum[v];
	}
	num+=n-1+(sum[rt]-1)*(n-sum[rt]);
	if(num&1)
		ans^=val[rt];
}
int main() 
{
	cin>>n;
	init();
	for(int i=0;i<n-1;i++)
	{
		LL a,b;
		cin>>a>>b;
		addedge(a,b);
		addedge(b,a);
	}
	for(int i=1;i<=n;i++)
		cin>>val[i];
	book[1]=true;
	dfs(1);
	cout << ans << endl;
	return 0;
}

猜你喜欢

转载自blog.csdn.net/wwwlps/article/details/88541114