牛客練習賽32B Xor Path (樹形dp)
時間限制:C/C++ 1秒,其他語言2秒
空間限制:C/C++ 262144K,其他語言524288K64bit IO Format: %lld
題目描述
給定一棵n個點的樹,每個點有權值 。定義 表示 到 的最短路徑上,所有點的點權異或和。 對於 ,求所有 的異或和。輸入描述:
輸出描述:
輸出一個整數,表示所有
的異或和,其中
。示例1
輸入
4 1 2 1 3 1 4 1 2 3 4
輸出
5
說明
備註:
題目大意:
給你一棵樹,每個節點有一個權值。path[i,j]記錄i到j的最短路徑上所有節點權值的抑或。求所有path[i,j]的抑或(i=1~n-1,j=i+1~n)。注意(i,j)是有序實數對哦。
其實就是求每個點在所有最短路徑中經歷了幾次。
樹形dp就好了。假設1是樹的根,sum[]記錄子樹的大小。dp過程還是有點妙噠。見程式碼。
#include <cstdio> #include <iostream> #include <algorithm> #include <cstring> #include <string> #include <cmath> #include <queue> #include <deque> #include <stack> #include <map> #include <set> typedef long long ll; const int mod=1000000007; const int inf=1000000000; const int maxn=500000; const int maxm=200; int n; int to[maxn*2+5]; int next[maxn*2+5]; int head[maxn+5],cnt; int val[maxn+5]; ll times[maxn+5]; int dfs(int x,int fa) { int sum=0; for(int i=head[x];i!=-1;i=next[i]) { int l=to[i]; if(l!=fa) { int temp=dfs(l,x); times[x]+=(ll)sum*temp; sum+=temp; } } times[x]+=(ll)sum*(n-1-sum); times[x]+=n-1; return sum+1; } int main() { scanf("%d",&n); memset(head,-1,sizeof(head)); cnt=0; for(int i=1,a,b;i<=n-1;i++) { scanf("%d%d",&a,&b); to[cnt]=b;next[cnt]=head[a];head[a]=cnt++; to[cnt]=a;next[cnt]=head[b];head[b]=cnt++; } for(int i=1;i<=n;i++) scanf("%d",val+i); memset(times,0,sizeof(times)); dfs(1,-1); int ans=1^1; for(int i=1;i<=n;i++) { if(times[i]%2==0) { val[i]^=val[i]; } ans^=val[i]; //printf("%lld %d\n",times[i],ans); } printf("%d\n",ans); return 0; }View Code