牛客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;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值