牛客网 272B Xor Path(树上操作)

题目链接:Xor Path

题意:每个顶点的点权为Ai,任意两点路径上点权异或和为Path(i,j),求所有Path(i,j)和。

题解:考虑每个顶点被用到的次数,分以下三种情况:

1.本身和其他顶点:n-1

2.该顶点上面的顶点(k)和下面的顶点(m)通过该点进行连接:k*m

3.该顶底下面的顶点通过该点进行连接(上面顶点不用的原因是:从上层层下来,已经记录过。):任意两个子树个数相乘之和。

第三种情况直接算会超时,我们需要优化一下,考虑下如果子树个数为偶数相当于没有贡献,所以只要考虑子树个数为奇数的即可,最后判断下C(cnt,2)是否为奇数,奇数的话贡献+1。

 1 #include <cstdio>
 2 #include <vector>
 3 using namespace std;
 4 
 5 typedef long long ll;
 6 const int N=5e5+10;
 7 int a[N],ans=0;
 8 ll sz[N],n;
 9 vector <int> E[N];
10 
11 void dfs(int u,int fa){
12     sz[u]=1;
13     ll sum=0,cnt=0;
14     for(int i=0;i<E[u].size();i++){
15         int v=E[u][i];
16         if(v!=fa){
17             dfs(v,u);
18             sz[u]+=sz[v];
19             if(sz[v]%2==1) cnt++;
20         }
21     }
22     //第三种情况
23     if((cnt*(cnt-1)/2)%2) sum++;
24     //n-1为第一种情况,(sz[u]-1)*(n-sz[u])为第二种情况.
25     sum=(sum+(n-1)+(sz[u]-1)*(n-sz[u])%2)%2;
26     if(sum%2==1) ans^=a[u];
27 }
28 
29 int main(){
30     scanf("%d",&n);
31     for(int i=1;i<n;i++){
32         int u,v;
33         scanf("%d%d",&u,&v);
34         E[u].push_back(v);
35         E[v].push_back(u);
36     }
37     for(int i=1;i<=n;i++) scanf("%d",&a[i]);
38     dfs(1,0);
39     printf("%d\n",ans);
40     return 0;
41 }
View Code

 

posted @ 2018-11-30 22:38  pavtlly  阅读(315)  评论(0编辑  收藏  举报