1. 程式人生 > >cogs 2478. [HZOI 2016]簡單的最近公共祖先

cogs 2478. [HZOI 2016]簡單的最近公共祖先

lld fault 兩節點 有根樹 cnblogs ont 給定 tar algo

2478. [HZOI 2016]簡單的最近公共祖先

★☆ 輸入文件:easy_LCA.in 輸出文件:easy_LCA.out 簡單對比
時間限制:2 s 內存限制:128 MB

【題目描述】

給定一棵有n個節點的有根樹,根節點為1,每個節點有一個權值wi,求

技術分享

即求所有無序節點對的LCA的權值之和。

樹的節點編號為1~n,LCA表示兩節點的最近公共祖先,即在它們的所有公共祖先中離根節點最遠的節點。

【輸入格式】

第一行一個整數n,表示節點數。

第二行n個正整數,表示每個點的權值。

以下n-1行每行兩個整數x,y,表示樹上有一條邊連接節點x和節點y。

【輸出格式】

一個整數,表示答案。

【樣例輸入】

3
1 2 3
1 2
1 3

【樣例輸出】

9

【數據範圍與約定】

對於30%的數據,n<=1000。

對於60%的數據,n<=100000。

對於100%的數據,1<=n<=1000000,0<wi<=1000000。

【來源】

HZOI 2016

思路:從數據範圍來看,去n^2枚舉i,j進行計算lca肯定不行,所以轉換思想找規律。

可以發現ans+=w[i]*孩子的數量+子樹1*子樹2+子樹1*子樹3+······

錯因:數組越界。

#include<iostream>
#include
<cstdio> #include<cstring> #include<algorithm> #define MAXN 3000000 using namespace std; int n,tot; long long ans; int w[MAXN],size[MAXN],dad[MAXN]; int to[MAXN],head[MAXN],net[MAXN]; void add(int u,int v){ to[++tot]=v;net[tot]=head[u];head[u]=tot; to[++tot]=u;net[tot]=head[v];head[v]=tot; }
void dfs(int now){ size[now]=1; for(int i=head[now];i;i=net[i]) if(dad[now]!=to[i]){ dad[to[i]]=now; dfs(to[i]); ans+=1ll*size[now]*size[to[i]]*w[now]; size[now]+=size[to[i]]; } } int main(){ freopen("easy_LCA.in","r",stdin); freopen("easy_LCA.out","w",stdout); scanf("%d",&n); for(int i=1;i<=n;i++){ scanf("%d",&w[i]); ans+=w[i]; } for(int i=1;i<n;i++){ int x,y; scanf("%d%d",&x,&y); add(x,y); } dfs(1); printf("%lld",ans); }

cogs 2478. [HZOI 2016]簡單的最近公共祖先