题意
求出树上所有路径的最大值和最小值之差的和。
题解
套路题,考虑每个点对答案的贡献,把删点变成加点,遍历一遍就OK。
代码
#include<bits/stdc++.h>
using namespace std;
typedef double db;
typedef long long ll;
typedef unsigned long long ull;
const int nmax = 1e6+7;
const int INF = 0x3f3f3f3f;
const ll LINF = 0x3f3f3f3f3f3f3f3f;
const ull p = 67;
const ull MOD = 1610612741;
int head[nmax],fa[nmax],sz[nmax],tot,n;
ll ans;
bool visit[nmax];
struct Node {
int id; ll val;
}node[nmax];
struct edge{
int to,nxt;
}e[nmax<<1];
int findset(int x){
int rt = x, temp;
while(fa[rt] != rt) rt = fa[rt];
while(x != rt){
temp = fa[x];
fa[x] = rt;
x = temp;
}
return rt;
}
void add(int u, int v){e[tot].to = v , e[tot].nxt = head[u], head[u] = tot++;}
bool cmp(Node a, Node b){return a.val > b.val;}
void getans(Node & u){
for(int i = head[u.id];i!=-1;i = e[i].nxt){
int v = e[i].to; v = findset(v);
if(!visit[v]) continue;
else{
ans += 1ll * sz[u.id] * sz[v] * u.val;
fa[v] = u.id; sz[u.id] += sz[v];
}
}
u.val = -u.val;
}
int main(){
memset(head,-1,sizeof head);
scanf("%d",&n);
for(int i = 1;i<=n;++i){
fa[i] = i, sz[i] = 1;
scanf("%I64d",&node[i].val);
node[i].id = i;
}
int u,v;
for(int i = 1;i<n;++i){
scanf("%d %d",&u,&v);
add(u,v), add(v,u);
}
sort(node+1,node+1+n,cmp);
for(int i = n;i>=1;--i){
getans(node[i]);
visit[node[i].id] = true;
}
for(int i = 1;i<=n;++i) visit[i] = false, sz[i] = 1, fa[i] = i;
for(int i = 1;i<=n;++i){
getans(node[i]);
visit[node[i].id] = true;
}
printf("%I64d\n",ans);
return 0;
}