連接:https://ac.nowcoder.com/acm/contest/2995/E
來源:牛客網
卡特莉正在爬樹,此時她又在樹梢發現了一個謎題,爲了避免令她分心以致於發生意外,請你幫她解決這個問題。
具體地來講,咱們定義樹上從u到v簡單路徑上全部點權中最大值與最小值的差值爲這條路徑的"平衡值",記爲balance(u,v)。
node
首先,把這個式子拆成兩部分,一部分計算最大值的和,另外一部分計算最小值的和。ios
如何計算最大值的和?c++
將點按點權從小到大排序,從小到大遍歷每一個點u,記u爲訪問過,找u連的點v,若是v訪問過了,那麼說明v確定比u小,因此u的權值在這兩個集合做爲最大值,乘上sz[fu]和sz[fv]即爲u對答案的貢獻。可能會有疑問爲啥要乘上sz[fu],乘上sz[fv]不就是u對v所在集合的貢獻嗎?實則否則,好比看樣例:git
1
10
9 9 6 2 4 5 8 5 5 6
2 1
3 1
4 3
5 3
6 4
7 2
8 4
9 5
10 3spa
藍色表示每一個點按順序更新後所在集合的sz,當遍歷到u=2的時候,發現連的點7和1都訪問過,說明權值都是小於等於9的,因此將2和7合併後,u所在集合的sz變成了2,那麼2再和1合併時,不只2能夠做爲1所在集合的點的最大值,並且7這個點是能夠陪着2一塊兒連向1所在集合的,由於最大值依然是2這個點。code
對於最小值的和的求法是相似的,按權值從大到小排序……blog
#include<bits/stdc++.h> using namespace std; #define inf 0x3f3f3f3f #define ll long long const int N=5e5+5; const int mod=1e9+7; const double eps=1e-8; const double PI = acos(-1.0); #define lowbit(x) (x&(-x)) int read() { int x=0; char ch=getchar(); while(!isdigit(ch)) { ch=getchar(); } while(isdigit(ch)) { x=x*10+(ch-'0'); ch=getchar(); } return x; } struct node { ll x,w; }a[N]; bool cmp1(node a,node b) { return a.w<b.w; } bool cmp2(node a,node b) { return a.w>b.w; } vector<int> g[N]; ll pre[N],mx[N],mn[N],sz[N],vis[N]; ll find(ll x) { if(x==pre[x]) return x; return pre[x]=find(pre[x]); } int main() { std::ios::sync_with_stdio(false); int t=read(); while(t--) { int n=read(); for(int i=1; i<=n; i++) { g[i].clear(); a[i].w=read(); a[i].x=i; mx[i]=mn[i]=a[i].w; } for(int i=1; i<n; i++) { int u=read(),v=read(); g[u].push_back(v); g[v].push_back(u); } sort(a+1,a+n+1,cmp1); for(int i=1; i<=n; i++) pre[i]=i,sz[i]=1,vis[i]=0; ll ans1=0; for(int i=1; i<=n; i++) { ll u=a[i].x,fu=find(u); vis[u]=1; for(int j:g[u]) { if(!vis[j]) continue; int fj=find(j); pre[fj]=fu; ans1=(ans1+sz[fu]*sz[fj]%mod*a[i].w%mod)%mod; (sz[fu]+=sz[fj])%=mod; } // cout<<u<<" "<<sz[fu]<<endl; } // cout<<ans1<<endl; sort(a+1,a+1+n,cmp2); for(int i=1; i<=n; i++) pre[i]=i,sz[i]=1,vis[i]=0; ll ans2=0; for(int i=1; i<=n; i++) { int u=a[i].x,fu=find(u); vis[u]=1; for(int j:g[u]) { if(!vis[j]) continue; int fj=find(j); pre[fj]=fu; ans2=(ans2+sz[fu]*sz[fj]%mod*a[i].w%mod)%mod; (sz[fu]+=sz[fj])%=mod; } // cout<<u<<" "<<sz[fu]<<endl; } // cout<<ans2<<endl; cout<<(ans1%mod-ans2%mod+mod)%mod<<endl; } return 0; }