1. 程式人生 > >牛客11月1日 區區區間間間 線段樹版

牛客11月1日 區區區間間間 線段樹版

題意;

給定一個長度為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;
}