题目大意:
定义
I
(
x
,
y
)
为
x
到
y
路
径
上
最
大
值
和
最
小
值
之
差
I(x,y)为x到y路径上最大值和最小值之差
I(x,y)为x到y路径上最大值和最小值之差
现在叫你求
∑
i
=
1
n
∑
j
=
i
n
I
(
x
,
y
)
\sum_{i=1}^ {n}\sum_{j=i}^nI(x,y)
i=1∑nj=i∑nI(x,y)
解题思路:
- 首先我们可以这么看对于一个点我们可以去看看假设这个点是路径上面的最大值,有多少条路径?然后我们再去看看这个点是多少路径上的最小值贡献相减就可以了!!
- 但是怎么求?我们可以把点按照权值进行升序排序,假设我们先把树给清空然后点一个个插进行当插进一个新的点的时候,我们发现这个树里面的点权值都比你现在插进来的点小!!
- 然后插入的点我们去访问周围的点,去统计路径就可以了
- 路径分两种:1.是一个块里面的路径,2是两个块直接的路径
AC code
#include <bits/stdc++.h>
#define mid ((l + r) >> 1)
#define Lson rt << 1, l , mid
#define Rson rt << 1|1, mid + 1, r
#define ms(a,al) memset(a,al,sizeof(a))
#define log2(a) log(a)/log(2)
#define lowbit(x) ((-x) & x)
#define IOS std::ios::sync_with_stdio(0); cin.tie(0); cout.tie(0)
#define INF 0x3f3f3f3f
#define LLF 0x3f3f3f3f3f3f3f3f
#define f first
#define s second
#define endl '\n'
using namespace std;
const int N = 2e6 + 10, mod = 1e9 + 9;
const int maxn = N;
const long double eps = 1e-5;
const int EPS = 500 * 500;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int> PII;
typedef pair<ll,ll> PLL;
typedef pair<double,double> PDD;
template<typename T> void read(T &x) {
x = 0;char ch = getchar();ll f = 1;
while(!isdigit(ch)){if(ch == '-')f*=-1;ch=getchar();}
while(isdigit(ch)){x = x*10+ch-48;ch=getchar();}x*=f;
}
template<typename T, typename... Args> void read(T &first, Args& ... args) {
read(first);
read(args...);
}
inline void write(__int128 x) {
if(x<0)
{
putchar('-');
x=-x;
}
if(x>9)
write(x/10);
putchar(x%10+'0');
}
ll sum[2];
vector<int> G[maxn];
struct node {
ll val;
int id;
}arr[maxn];
bool cmpup(node a, node b) {
return a.val < b.val;
}
bool cmpdown(node a, node b) {
return a.val > b.val;
}
int n;
struct dsu {
int fa[maxn], siz[maxn];
bool vis[maxn];
inline void init(int n) {
for(int i = 1; i <= n; ++ i) vis[i] = 0, fa[i] = i, siz[i] = 1;
}
inline int find(int x) {
return x == fa[x] ? x : fa[x] = find(fa[x]);
}
inline void Union(int u, int v) {
int fu = find(u), fv = find(v);
if(fu == fv) return;
fa[fu] = fv;
siz[fv] += siz[fu];
}
}dsu;
void work(int idx) {
for(int i = 1; i <= n; ++ i) {
int id = arr[i].id;
ll ans = 0;
ll pre = 0;
for(auto it : G[id]) {
int fit = dsu.find(it);
// cout << "it = " << it << " " << fit << " " << dsu.siz[fit] << endl;
if(!dsu.vis[it]) continue;// 访问周围的点
if(pre == 0) {
pre = dsu.siz[fit];
} else {
ans += dsu.siz[fit] * pre;
pre += dsu.siz[fit];
}
}
for(auto it : G[id]) if(dsu.vis[it]) dsu.Union(it,id); //合并点
dsu.vis[id] = 1;
sum[idx] += (ans + pre) * arr[i].val;
// cout << sum[idx] << endl;
}
}
int main() {
IOS;
cin >> n;
for(int i = 1; i <= n; ++ i) cin >> arr[i].val,arr[i].id = i;
for(int i = 2; i <= n; ++ i) {
int u, v;
cin >> u >> v;
G[u].push_back(v);
G[v].push_back(u);
}
sort(arr+1,arr+1+n,cmpup);
dsu.init(n);
work(0);
// cout << "---\n";
// cout << sum[0] << endl;
sort(arr+1,arr+1+n,cmpdown);
dsu.init(n);
work(1);
cout << sum[0] - sum[1];
// write(sum[0] - sum[1]);
}
/*
5
1 1 1 2 2
1 2
3 4
5 2
3 1
*/