n<=1e6的树问所有路径的极差之和。
被遗忘的套路。。。以后绝对不会再忘了QAQ
只要算最大值之和即可,最小值同理。数字从大到小排序(反正都是要排序的,如果从大到小不行等会反过来试试),然后逐个考虑贡献,这样的话考虑完一个点就得把这个点周围所有的边断掉表示经过这些边的路径(即经过当前点的路径)不再计算。断边麻烦,连边简单,那就整个反过来,数字从小到大排序,逐个考虑贡献,考虑完这个点把他和周围的点连起来即可。
1 #include<string.h> 2 #include<stdlib.h> 3 #include<stdio.h> 4 #include<math.h> 5 //#include<assert.h> 6 #include<algorithm> 7 //#include<iostream> 8 //#include<bitset> 9 using namespace std; 10 11 int n; 12 #define maxn 1000011 13 struct Edge{int to,next;}edge[maxn<<1]; int first[maxn],le=2,val[maxn]; 14 void in(int x,int y) {Edge &e=edge[le]; e.to=y; e.next=first[x]; first[x]=le++;} 15 void insert(int x,int y) {in(x,y); in(y,x);} 16 17 int ufs[maxn],size[maxn]; 18 int find(int x) {return x==ufs[x]?x:(ufs[x]=find(ufs[x]));} 19 20 #define LL long long 21 LL ans=0; 22 23 int num[maxn]; 24 bool cmp(const int &a,const int &b) {return val[a]<val[b];} 25 26 bool vis[maxn]; 27 void solve() 28 { 29 memset(vis,0,sizeof(vis)); 30 for (int i=1;i<=n;i++) ufs[i]=i,size[i]=1; 31 for (int i=1;i<=n;i++) 32 { 33 int now=num[i]; vis[now]=1; 34 LL tmp=1,last=0; 35 for (int j=first[now];j;j=edge[j].next) 36 { 37 const Edge &e=edge[j]; if (!vis[e.to]) continue; 38 int x=find(now),y=find(e.to); 39 tmp+=(last+1)*size[y]; last+=size[y]; 40 ufs[y]=x; size[x]+=size[y]; 41 } 42 ans+=tmp*val[now]; 43 } 44 } 45 46 int main() 47 { 48 scanf("%d",&n); 49 for (int i=1;i<=n;i++) scanf("%d",&val[i]); 50 for (int i=1,x,y;i<n;i++) 51 { 52 scanf("%d%d",&x,&y); 53 insert(x,y); 54 } 55 for (int i=1;i<=n;i++) num[i]=i; 56 sort(num+1,num+1+n,cmp); solve(); 57 for (int i=1;i<=n;i++) val[i]=-val[i]; 58 sort(num+1,num+1+n,cmp); solve(); 59 printf("%lld ",ans); 60 return 0; 61 }