牛客16736 极差

题目链接

一、题意

3个序列a,b,c,计算 \sum_{l=1}^{n}\sum_{r=l}^{n}f(l,r)*g(l,r)*h(l,r)\;\;(mod \;\; 2^{32})

f(l,r)=\left | max\left \{a[l],a[l+1],...,a[r] \right \} - min\left \{a[l],a[l+1],...,a[r] \right \} \right |

g(l,r)=\left | max\left \{b[l],b[l+1],...,b[r] \right \} - min\left \{b[l],b[l+1],...,b[r] \right \} \right |

h(l,r)=\left | max\left \{c[l],c[l+1],...,c[r] \right \} - min\left \{c[l],c[l+1],...,c[r] \right \} \right |

数据范围:1\leqslant n \leqslant 10^5,1\leqslant a_i , b_i , c_i \leqslant 10^9

二、题解

题是真好,我是真菜,这个套路没见过。

考虑枚举r,快速统计所有的 l 对应的答案。

单调队列维护a[1,...,r]的最大值和最小值,b[1,...,r]的最大值和最小值,c[1,...,r] 的最大值和最小值。

线段树下标 i 对应的值是 [i,r] 的最大值 - 最小值。

需要开7棵线段树,分别维护序列 a,b,c,a*b,a*c,b*c,a*b*c 。

具体细节还是看代码吧。

三、代码 

#include<bits/stdc++.h>
#define pb push_back
#define fi first
#define se second
#define sz(x)  (int)x.size()
#define cl(x)  x.clear()
#define all(x)  x.begin() , x.end()
#define rep(i , x , n)  for(int i = x ; i <= n ; i ++)
#define per(i , n , x)  for(int i = n ; i >= x ; i --)
#define mem0(x)  memset(x , 0 , sizeof(x))
#define mem_1(x)  memset(x , -1 , sizeof(x))
#define mem_inf(x)  memset(x , 0x3f , sizeof(x))
#define debug(x)  cerr << #x << " = " << x << '\n'
#define ddebug(x , y)  cerr << #x << " = " << x << "   " << #y << " = " << y << '\n'
#define ios std::ios::sync_with_stdio(false) , cin.tie(0)
#define int unsigned int
using namespace std ;
typedef long long ll ;
typedef long double ld ;
typedef pair<int , int> pii ;
typedef pair<ll , ll> pll ;
const int mod = 998244353 ;
const int maxn = 2e5 + 10 ;
const int inf = 0x3f3f3f3f ;
const double eps = 1e-6 ; 
mt19937  rnd(chrono::high_resolution_clock::now().time_since_epoch().count()) ; 
int n , x[maxn][5] ;
int mx[maxn][5] , p_max[5] ;
int mn[maxn][5] , p_min[5] ;
int ans = 0 ;
struct seg_tree
{
    int sum[maxn << 2][10] , add[maxn << 2][10] ;    
    int ls(int x){ return x << 1 ; }
    int rs(int x){ return x << 1 | 1 ; }
    void push_up(int p)
    { 
        rep(i , 1 , 7)  sum[p][i] = sum[ls(p)][i] + sum[rs(p)][i] ; 
    }
    void f(int id , int len , int k , int op)
    {
        if(op == 1) // a
        {
            sum[id][1] += k * len ; // a
            sum[id][4] += k * sum[id][2] ; // ab b
            sum[id][5] += k * sum[id][3] ; // ac c
            sum[id][7] += k * sum[id][6] ; // abc bc
        }
        else if(op == 2) // b
        {
            sum[id][2] += k * len ; // b
            sum[id][4] += k * sum[id][1] ; // ab a
            sum[id][6] += k * sum[id][3] ; // bc c
            sum[id][7] += k * sum[id][5] ; // abc ac
        }
        else // c
        {
            sum[id][3] += k * len ; // c
            sum[id][5] += k * sum[id][1] ; // ac a
            sum[id][6] += k * sum[id][2] ; // bc b
            sum[id][7] += k * sum[id][4] ; // abc ab
        }
        add[id][op] += k ;
    }
    void push_down(int id , int l , int r)
    {
        int mid = (l + r) >> 1 ;
        rep(op , 1 , 3)
          if(add[id][op] != 0)
          {
              f(ls(id) , mid - l + 1 , add[id][op] , op) ;
              f(rs(id) , r - mid , add[id][op] , op) ;
              add[id][op] = 0 ;
          }
    }
    void update(int id , int l , int r , int x , int y , int k , int op)
    {
        if(x > y || x > r || y < l)  return ; //避免越界。
        if(x <= l && r <= y)  
        {
            f(id , r - l + 1 , k , op) ;
            return ;
        }
        push_down(id , l , r) ;
        int mid = (l + r) >> 1 ;
        if(x <= mid) update(ls(id) , l , mid , x , y , k , op) ;
        if(y > mid)  update(rs(id) , mid + 1 , r , x , y , k , op) ;
        push_up(id) ;
    }
} seg ;
signed main()
{
    ios ;
    cin >> n ;
    rep(j , 1 , 3)  rep(i , 1 , n)  cin >> x[i][j] ;
    rep(i , 1 , n)
    {
        rep(j , 1 , 3)
        {
            //max
            while(p_max[j] >= 1 && x[i][j] >= x[mx[p_max[j]][j]][j])
            {
                seg.update(1 , 1 , n , mx[p_max[j] - 1][j] + 1 , mx[p_max[j]][j] , -x[mx[p_max[j]][j]][j] , j) ;
                p_max[j] -- ;
            }
            mx[++ p_max[j]][j] = i ;
            seg.update(1 , 1 , n , mx[p_max[j] - 1][j] + 1 , mx[p_max[j]][j] , x[mx[p_max[j]][j]][j] , j) ;
            //min
            while(p_min[j] >= 1 && x[i][j] <= x[mn[p_min[j]][j]][j])
            {
                seg.update(1 , 1 , n , mn[p_min[j] - 1][j] + 1  , mn[p_min[j]][j] , x[mn[p_min[j]][j]][j] , j) ;
                p_min[j] -- ;
            }
            mn[++ p_min[j]][j] = i ;
            seg.update(1 , 1 , n , mn[p_min[j] - 1][j] + 1  , mn[p_min[j]][j] , -x[mn[p_min[j]][j]][j] , j) ;
        }
        ans += seg.sum[1][7] ;
    }
    cout << ans << '\n' ;
    return 0 ;
}

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值