Time Limit: 4000/2000 MS (Java/Others) Memory Limit: 163840/163840 K (Java/Others)
Total Submission(s): 1149 Accepted Submission(s): 457
php
//作法很好想但实现很难,两条边以上的路径有两种,一种是儿子节点及其后代和父亲链接的路径 //另外一种是兄弟之间链接的路径但处理兄弟之间组成的路径很差处理。dp[i]存i节点以及其后代的 //权值和,cntp[i]存i节点以及其后代中共有多少个节点。好难。 #include<iostream> #include<cstdio> #include<cstring> using namespace std; typedef long long ll; int n,head[300009],tol,pa[300009],cntp[300009],val[300009],S[300009]; ll dp[300009],vc[300009],vw[300009],ans; struct node{ int v,w,next; }nodes[600009]; void Add(int x,int y,int z){ nodes[tol].v=y; nodes[tol].w=z; nodes[tol].next=head[x]; head[x]=tol++; } void dfs(int u,int fa){ cntp[u]=1;dp[u]=val[u]; ll sum=0; for(int i=head[u];i!=-1;i=nodes[i].next){ int v=nodes[i].v; if(v==fa) continue; pa[v]=nodes[i].w; dfs(v,u); } int c=0; for(int i=head[u];i!=-1;i=nodes[i].next){ int v=nodes[i].v; if(v==fa) continue; cntp[u]+=cntp[v]; if(!vc[nodes[i].w]) S[++c]=nodes[i].w; vc[nodes[i].w]+=cntp[v]; vw[nodes[i].w]+=dp[v]; if(nodes[i].w!=pa[u])//更新u dp[u]+=dp[v]+1ll*cntp[v]*val[u]; ans+=dp[v]+1ll*cntp[v]*val[u];//和父亲链接 sum+=dp[v]; ans+=((sum-vw[nodes[i].w])*cntp[v]+dp[v]*(cntp[u]-1-vc[nodes[i].w])+1ll*val[u]*cntp[v]*(cntp[u]-1-vc[nodes[i].w]));//兄弟之间链接 } cntp[u]-=vc[pa[u]];//减去颜色冲突的 while(c){ vc[S[c]]=0; vw[S[c--]]=0; } } int main() { while(scanf("%d",&n)==1){ int x,y,z; tol=0; memset(head,-1,sizeof(head)); for(int i=1;i<=n;i++) scanf("%d",&val[i]); for(int i=1;i<n;i++){ scanf("%d%d%d",&x,&y,&z); Add(x,y,z); Add(y,x,z); } ans=0;pa[1]=0; dfs(1,0); printf("%I64d\n",ans); } return 0; }