题意;
给定一个长度为n的序列,计算所有区间的 ‘最大值-最小值’ 之和;
思路:
分别计算所有区间的最大值的和,和最小值的和;
这里我用线段树维护区间最大(最小)值和位置,然后能知道当前值作为最大值能贡献的区间个数,递归的处理每个区间,
处理最小值同理;
更加详细思路讲解:https://blog.csdn.net/xiang_6/article/details/83655162 (不是线段树)
#include<bits/stdc++.h>
using namespace std;
#define out fflush(stdout)
#define fast ios::sync_with_stdio(0),cin.tie(0);
#define FI first
#define SE second
typedef long long ll;
typedef pair<ll,ll> P;
const int maxn = 2e5 + 7;
const int INF = 0x3f3f3f3f;
ll n;
ll a[maxn];
ll ans1 = 0, ans2 = 0;
struct node {
ll id, l, r;
ll max_, pos;
}tr[maxn<<2], ti[maxn<<2];
void push_up(ll id) {
if(tr[id<<1].max_ > tr[id<<1 | 1].max_) {
tr[id].max_ = tr[id<<1].max_;
tr[id].pos = tr[id<<1].pos;
}
else {
tr[id].max_ = tr[id<<1 | 1].max_;
tr[id].pos = tr[id<<1 | 1].pos;
}
}
void build(ll id, ll l, ll r) {
tr[id].id = id; tr[id].l = l; tr[id].r = r;
if(l == r) {
tr[id].max_ = a[l]; tr[id].pos = l;
return;
}
ll mid = (l + r) >> 1;
build(id<<1, l, mid);
build(id<<1 | 1, mid+1, r);
push_up(id);
}
void push_up1(ll id) {
if(ti[id<<1].max_ < ti[id<<1 | 1].max_) {
ti[id].max_ = ti[id<<1].max_;
ti[id].pos = ti[id<<1].pos;
}
else {
ti[id].max_ = ti[id<<1 | 1].max_;
ti[id].pos = ti[id<<1 | 1].pos;
}
}
void build1(ll id, ll l ,ll r) {
// cout << " min -- " << id << " " << l << " " << r << endl;
ti[id].id = id; ti[id].l = l; ti[id].r = r;
if(l == r) {
ti[id].max_ = a[l]; ti[id].pos = l;
return;
}
ll mid = (l + r) >> 1;
build1(id<<1, l, mid);
build1(id<<1 | 1, mid+1, r);
push_up1(id);
}
void init() {
scanf("%lld", &n);
for(int i = 1; i <= n; ++i) {
scanf("%lld", &a[i]);
}
build(1, 1, n);
build1(1, 1, n);
ans1 = 0, ans2 = 0;
}
P query(ll id, ll l, ll r) {
ll l_ = tr[id].l, r_ = tr[id].r;
if(r < l) return P(0, 0);
if(l == l_ && r == r_) return P(tr[id].max_, tr[id].pos);
ll mid = (l_ + r_) >> 1;
// cout << l << " + " << r << " " << l_ << " " << r_ << " - " << mid << endl;
if(r <= mid) {
return query(id<<1, l, r);
}
else if(l > mid) {
return query(id<<1 | 1, l, r);
}
else {
P t1 = query(id<<1, l, mid);
P t2 = query(id<<1 | 1, mid+1, r);
if(t1.FI > t2.FI) {
return t1;
}
else return t2;
}
}
P query1(ll id, ll l, ll r) {
ll l_ = ti[id].l, r_ = ti[id].r;
if(r < l) return P(0, 0);
if(l == l_ && r == r_) return P(ti[id].max_, ti[id].pos);
ll mid = (l_ + r_) >> 1;
if(r <= mid) {
return query1(id<<1, l, r);
}
else if(l > mid) {
return query1(id<<1 | 1, l, r);
}
else {
P t1 = query1(id<<1, l, mid);
P t2 = query1(id<<1 | 1, mid+1, r);
if(t1.FI < t2.FI) {
return t1;
}
else return t2;
}
}
void solve(ll l, ll r) {
if(r - l <= 0) return;
P pos = query(1, l, r);
ll t = pos.SE, v = pos.FI;
ans1 += (ll)( t-l + r-t + (t-l)*(r-t))*(ll)v;
solve(l, t-1);
solve(t+1, r);
}
void solve1(ll l, ll r) {
if(r - l <= 0) return;
P pos = query1(1, l, r);
ll t = pos.SE, v = pos.FI;
ans2 += (ll)( t-l + r-t + (t-l)*(r-t))*(ll)v;
solve1(l, t-1);
solve1(t+1, r);
}
int main() {
int T; scanf("%d", &T);
while(T--) {
init();
solve(1, n);
solve1(1, n);
printf("%lld\n", ans1-ans2);
}
return 0;
}