/*
分析:
dfs,也算是树形dp吧。
难度一般,不过细节部分处理的我快要吐血了。。。
以前碰到过这个题,不过想出来的方法觉得麻烦,细节
没有处理好,就搁置了。。。后来又碰到了、又又碰到了、、
又又又碰到了。。。擦!不能忍了!真的不能忍了!遂继续
琢磨自己的方法,发现也没有别的更好的方法了(至少咱这
菜鸟木有发现囧~),然后狠心灭之~
方法倒是很好想到,求ans的时候一遍dfs就行了,处理
当前node怎么合并其每一个一代儿子了,由于还要判断到儿
子的边的颜色,O(n^2)的挑出来俩比较比较、再挑出来俩比
较比较铁定不行的,所以要先对到儿子的边、按照颜色升序
(或降序)排序,然后合并既可。
2013-04-16
*/
分析:
dfs,也算是树形dp吧。
难度一般,不过细节部分处理的我快要吐血了。。。
以前碰到过这个题,不过想出来的方法觉得麻烦,细节
没有处理好,就搁置了。。。后来又碰到了、又又碰到了、、
又又又碰到了。。。擦!不能忍了!真的不能忍了!遂继续
琢磨自己的方法,发现也没有别的更好的方法了(至少咱这
菜鸟木有发现囧~),然后狠心灭之~
方法倒是很好想到,求ans的时候一遍dfs就行了,处理
当前node怎么合并其每一个一代儿子了,由于还要判断到儿
子的边的颜色,O(n^2)的挑出来俩比较比较、再挑出来俩比
较比较铁定不行的,所以要先对到儿子的边、按照颜色升序
(或降序)排序,然后合并既可。
2013-04-16
*/
#include"iostream"
#include"cstdio"
#include"vector"
#include"cstring"
#include"algorithm"
using namespace std;
const int N=300111;
int n,val[N];
struct node{
int cnt; //到达node的可行边的数量
__int64 sum,ans;//sum:到达node的可行边的价值;ans:node节点含其所有儿子、孙子、儿子的孙子、。。。的ans
}E[N];
struct Eage{
int f,t,c,next;
}eage[2*N],eage2[N];
int tot,tot2,head[N],head2[N];
void add(int a,int b,int c){
eage[tot].f=a;eage[tot].t=b;eage[tot].c=c;eage[tot].next=head[a];head[a]=tot++;
}
void add2(int a,int b,int c){
eage2[tot2].f=a;eage2[tot2].t=b;eage2[tot2].c=c;eage2[tot2].next=head2[a];head2[a]=tot2++;
}
int cmp(Eage n1,Eage n2){
return n2.c<n1.c;
}
int hash[N],num[N];
void dfs0(int s) //这个函数记录每个节点的儿子的个数,为了:二次建边以及对儿子节点按照颜色排序
{
int j,v;
num[s]=0;
hash[s]=1;
for(j=head[s];j!=-1;j=eage[j].next)
{
v=eage[j].t;
if(hash[v]) continue;
num[s]++;
dfs0(v);
}
}
void dfs1(int s) //对儿子排序
{
int j,v;
int sum=0;
vector<Eage> ttemp(num[s]);
hash[s]=1;
for(j=head[s];j!=-1;j=eage[j].next)
{
v=eage[j].t;
if(hash[v]) continue;
ttemp[sum++]=eage[j];
dfs1(v);
}
sort(ttemp.begin(),ttemp.end(),cmp);
for(j=0;j<sum;j++) add2(s,ttemp[j].t,ttemp[j].c);
}
void build_map()
{
int i;
int a,b,c;
tot=0;
memset(head,-1,sizeof(head));
for(i=1;i<n;i++)
{
scanf("%d%d%d",&a,&b,&c);
add(a,b,c);add(b,a,c);
}
memset(hash,0,sizeof(hash));
dfs0(1);
tot2=0;
memset(hash,0,sizeof(hash));
memset(head2,-1,sizeof(head2));
dfs1(1);
}
//返回node del,代表儿子的儿子到达儿子的边中,有哪些不可以用来到达当前node
node dfs2(int s,int pre) //pre是连到这个node(既s)的边的颜色
{
node now,del;
if(head2[s]==-1)
{
E[s].ans=E[s].sum=E[s].cnt=0;
now.sum=now.cnt=0;
return now;
}
int j,v,ppre=-1,cnt_temp,que_cnt; //ppre是当前node的前一个儿子的颜色;俩cnt是为了处理连续出现多个颜色一样的儿子
__int64 temp,temp2,sum_temp,que_sum;//俩sum也是为了处理连续出现多个颜色一样的儿子
cnt_temp=que_cnt=now.sum=now.cnt=0;
sum_temp=que_sum=E[s].ans=E[s].sum=E[s].cnt=0;
for(j=head2[s];j!=-1;j=eage2[j].next)
{
v=eage2[j].t;
del=dfs2(v,eage2[j].c);
if(eage2[j].c==pre)
{
now.cnt+=E[v].cnt-del.cnt+1;
now.sum+=E[v].sum-del.sum+(E[v].cnt-del.cnt+1)*val[s]+val[v];
}
if(head2[eage2[j].t]==-1)
{
temp=1;
temp2=val[s]+val[v];
}
else
{
temp=E[v].cnt-del.cnt+1;
temp2=E[v].sum-del.sum;
temp2+=temp*val[s]+val[v];
}
E[s].cnt+=(int)temp;
E[s].sum+=temp2;
E[s].ans+=E[v].ans+temp2;
if(eage2[j].c==ppre)
{
E[s].ans+=sum_temp*temp+cnt_temp*(E[v].sum-del.sum+val[v]);
que_cnt+=temp;
que_sum+=temp2;
}
else
{
sum_temp+=que_sum;
cnt_temp+=que_cnt;
E[s].ans+=sum_temp*temp+cnt_temp*(E[v].sum-del.sum+val[v]);
ppre=eage2[j].c;
que_cnt=temp;
que_sum=temp2;
}
}
return now;
}
int main()
{
int i;
while(scanf("%d",&n)!=-1)
{
for(i=1;i<=n;i++) scanf("%d",&val[i]);
if(n==1) {printf("0\n");continue;}
build_map();
memset(E,0,sizeof(E));
dfs2(1,-1);
printf("%I64d\n",E[1].ans);
}
return 0;
}