【51Nod1405】樹上距離和 二次掃描與換根法
阿新 • • 發佈:2018-11-25
continue 51nod max span ons its 轉移 rom ace
題目大意:給定一棵 N 個點的邊權均為 1 的樹,依次輸出每個點到其他各個點的距離和。
題解:首先任意選定一個節點為根節點,比如 1,第一遍 dfs 遍歷樹求出子樹大小、樹上前綴和。第二遍 dfs 遍歷這棵樹,求出各個點的距離和。
對於遍歷到的任意一個節點 i,對於與之相鄰的節點 j 來說,答案貢獻由 i 到 j 轉移首先減小了 \(size[j]*1\),同時增加了 \((n-size[j])*1\),因此可以直接得到\(dp[j]=dp[i]+n-size[j]*2\)。
代碼如下
#include <bits/stdc++.h> using namespace std; const int maxn=1e5+10; inline int read(){ int x=0,f=1;char ch; do{ch=getchar();if(ch==‘-‘)f=-1;}while(!isdigit(ch)); do{x=x*10+ch-‘0‘;ch=getchar();}while(isdigit(ch)); return f*x; } struct node{ int nxt,to; }e[maxn<<1]; int tot=1,head[maxn]; int n,size[maxn],sum[maxn],dp[maxn]; inline void add_edge(int from,int to){ e[++tot]=node{head[from],to},head[from]=tot; } void read_and_parse(){ n=read(); for(int i=1;i<n;i++){ int from=read(),to=read(); add_edge(from,to),add_edge(to,from); } } void dfs1(int u,int fa){ size[u]=1; for(int i=head[u];i;i=e[i].nxt){ int v=e[i].to;if(v==fa)continue; sum[v]=sum[u]+1; dfs1(v,u); size[u]+=size[v]; } dp[1]+=sum[u]; } void dfs2(int u,int fa){ for(int i=head[u];i;i=e[i].nxt){ int v=e[i].to;if(v==fa)continue; dp[v]=dp[u]+n-(size[v]<<1); dfs2(v,u); } } void solve(){ dfs1(1,0),dfs2(1,0); for(int i=1;i<=n;i++)printf("%d\n",dp[i]); } int main(){ read_and_parse(); solve(); return 0; }
【51Nod1405】樹上距離和 二次掃描與換根法