牛客网 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 }