1. 程式人生 > >牛客網 272B Xor Path(樹上操作)

牛客網 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