牛客11月1日 區區區間間間 線段樹版
阿新 • • 發佈:2018-11-13
題意;
給定一個長度為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; }