从任意一点开始深搜,对其所有的儿子按边的颜色排个序,然后在按这个序深搜和统计每颗子树。
搜索完毕之后向上返回pair<可以延伸到该点且最后一条边与由父节点到该点的边颜色不同的gorgeous边的条数 , 所有这种边分数的总和>。
每次深搜完一个子节点之后,增加的过这一点的gorgeous边的总分数为:
之前深搜的所有子节点向上返回的边数之和 * 当前子节点返回的分数 +
之前深搜的所有子节点向上返回的边数之和 * 当前子节点返回的边数 * 当前点的权。
#include<stdio.h>
#include<string.h>
#include<vector>
#include<algorithm>
using namespace std;
#define N 301000
int head[N],idx;
struct edge{
int v,color,nt;
edge(){}
edge(int v,int color,int nt):v(v),color(color),nt(nt){}
}e[N*2];
int n;
int pv[N];
__int64 ans;
bool cmp(int i,int j){
return e[i].color<e[j].color;
}
void dfs(int u,int f,__int64 &a,__int64 &b){
vector<int> v1;
bool flag=0;
for(int i=head[u];i!=-1;i=e[i].nt){
if(i==(f^1)) continue;
v1.push_back(i);
flag=1;
}
a=b=0;
if(!flag) return;
sort(v1.begin(),v1.end(),cmp);
int pre=-1,cnt=0;
vector<__int64>vx,vy;
__int64 x,y,num=0,ans1=0,ans2=0,sum=0;
for(int i=0;i<v1.size();i++){
int v=e[v1[i]].v,color=e[v1[i]].color;
dfs(v,v1[i],x,y);
if(f==-1||color!=e[f].color) a+=x+1,b+=pv[v]+y+(x+1)*pv[u];
num+=x+1,sum+=y+pv[v];
if(pre!=color)
{
vx.push_back(x+1);
vy.push_back(y+pv[v]);
cnt++;
}
else vx[cnt-1]+=x+1,vy[cnt-1]+=y+pv[v];
pre=color;
}
for(int i=0;i<cnt;i++){
ans2+=(vx[i]*pv[u]+vy[i]);
ans1+=(sum-vy[i])*vx[i]+(num-vx[i])*vy[i]+(num-vx[i])*vx[i]*pv[u];
}
ans+=ans2+ans1/2;
}
int main(){
while(scanf("%d",&n)!=EOF)
{
for(int i=1;i<=n;i++) scanf("%d",pv+i);
idx=0;
memset(head,-1,sizeof(head));
for(int i=1;i<n;i++){
int a,b,c;
scanf("%d%d%d",&a,&b,&c);
e[idx]=edge(b,c,head[a]);head[a]=idx++;
e[idx]=edge(a,c,head[b]);head[b]=idx++;
}
ans=0;
__int64 a,b;
dfs(1,-1,a,b);
printf("%I64d\n",ans);
}
}