• 极差 牛客-16736(单调栈,线段树)


    题意:

    给出三个长度为$n$的正整数序列,一个区间$[L,R]$的价值定义为:三个序列中,这个区间的极差(最大值与最小值之差)的乘积。
    求所有区间的价值之和。答案对$2^{32}$取模。

    思路:

    枚举右端点,设三个序列分别是$a,b,c$,线段树维护$a,b,c,ab,ac,bc,abc$的$max-min$的值。线段树每个单位区间$(x,x)$表示序列区间$(x,r)$的$max-min$的值。$a$的$max-min$改变,$ab,ac,abc$都改变。单调栈维护区间的最大最小值。

    代码:

      1 //#include<bits/stdc++.h>
      2 #include <set>
      3 #include <map>
      4 #include <stack>
      5 #include <cmath>
      6 #include <queue>
      7 #include <cstdio>
      8 #include <string>
      9 #include <vector>
     10 #include <cstring>
     11 #include <iostream>
     12 #include <algorithm>
     13 
     14 #define ll long long
     15 #define pll pair<ll,ll>
     16 #define pii pair<int,int>
     17 #define bug printf("*********
    ")
     18 #define FIN freopen("input.txt","r",stdin);
     19 #define FON freopen("output.txt","w+",stdout);
     20 #define IO ios::sync_with_stdio(false),cin.tie(0)
     21 #define ls root<<1
     22 #define rs root<<1|1
     23 #define pb push_back
     24 #define PI acos(-1.0)
     25 
     26 using namespace std;
     27 const int inf = 0x3f3f3f3f;
     28 const ll INF = 1e18 + 7;
     29 const int maxn = 1e5 + 5;
     30 const ll mod = 1ll << 32;
     31 const double eps = 1e-6;
     32 
     33 inline ll read() {
     34     bool f = 0;
     35     ll x = 0; char ch = getchar();
     36     while (ch < '0' || ch>'9') { if (ch == '-')f = 1; ch = getchar(); }
     37     while (ch >= '0' && ch <= '9') { x = (x << 3) + (x << 1) + (ch ^ 48); ch = getchar(); }
     38     return f ? -x : x;
     39 }
     40 
     41 ll gcd(ll a, ll b) {
     42     return b == 0 ? a : gcd(b, a % b);
     43 }
     44 
     45 ll tr[maxn << 2][8];
     46 ll lazy[maxn << 2][4];
     47 
     48 void push_up(int root) {
     49     for (int i = 1; i <= 7; ++i) {
     50         tr[root][i] = tr[ls][i] + tr[rs][i];
     51     }
     52 }
     53 
     54 void work(int root, ll x, int id, int len) {
     55     if (id == 1) {
     56         tr[root][1] += x * len;
     57         tr[root][4] += tr[root][2] * x;
     58         tr[root][5] += tr[root][3] * x;
     59         tr[root][7] += tr[root][6] * x;
     60     }
     61     else if (id == 2) {
     62         tr[root][2] += x * len;
     63         tr[root][4] += tr[root][1] * x;
     64         tr[root][6] += tr[root][3] * x;
     65         tr[root][7] += tr[root][5] * x;
     66     }
     67     else {
     68         tr[root][3] += x * len;
     69         tr[root][5] += tr[root][1] * x;
     70         tr[root][6] += tr[root][2] * x;
     71         tr[root][7] += tr[root][4] * x;
     72     }
     73     lazy[root][id] += x;
     74     lazy[root][id] %= mod;
     75     for (int i = 1; i <= 7; ++i) {
     76         tr[root][i] %= mod;
     77     }
     78 }
     79 
     80 void push_down(int root, int l, int r) {
     81     for (int i = 1; i <= 3; ++i) {
     82         if (lazy[root][i]) {
     83             int mid = (l + r) >> 1;
     84             work(ls, lazy[root][i], i, mid - l + 1);
     85             work(rs, lazy[root][i], i, r - mid);
     86             lazy[root][i] = 0;
     87         }
     88     }
     89 }
     90 
     91 void update(int root, int l, int r, int ql, int qr, ll x, int id) {
     92     if (l >= ql && r <= qr) {
     93         work(root, x, id, r - l + 1);
     94         return;
     95     }
     96     push_down(root, l, r);
     97     int mid = (l + r) >> 1;
     98     if (ql <= mid)    update(ls, l, mid, ql, qr, x, id);
     99     if (qr > mid)    update(rs, mid + 1, r, ql, qr, x, id);
    100     push_up(root);
    101 }
    102 
    103 int n;
    104 ll arr[4][maxn];
    105 int mx[4][maxn], mn[4][maxn];
    106 int px[4], pn[4];
    107 
    108 int main() {
    109     n = read();
    110     for (int i = 1; i <= 3; ++i) {
    111         for (int j = 1; j <= n; ++j) {
    112             arr[i][j] = read();
    113         }
    114     }
    115     ll ans = 0;
    116     for (int r = 1; r <= n; ++r) {
    117         for (int i = 1; i <= 3; ++i) {
    118             while (pn[i] && arr[i][mn[i][pn[i]]] >= arr[i][r]) {
    119                 update(1, 1, n, mn[i][pn[i] - 1] + 1, mn[i][pn[i]], arr[i][mn[i][pn[i]]], i);
    120                 --pn[i];
    121             }
    122             mn[i][++pn[i]] = r;
    123             update(1, 1, n, mn[i][pn[i] - 1] + 1, r, -arr[i][r], i);
    124 
    125             while (px[i] && arr[i][mx[i][px[i]]] <= arr[i][r]) {
    126                 update(1, 1, n, mx[i][px[i] - 1] + 1, mx[i][px[i]], -arr[i][mx[i][px[i]]], i);
    127                 --px[i];
    128             }
    129             mx[i][++px[i]] = r;
    130             update(1, 1, n, mx[i][px[i] - 1] + 1, r, arr[i][r], i);
    131         }
    132         ans += tr[1][7];
    133         ans %= mod;
    134     }
    135     cout << (ans + mod) % mod << endl;
    136 }
  • 相关阅读:
    C#面向对象三大特性:多态
    C#面向对象三大特性:继承
    C#面向对象三大特性:封装
    C# 函数
    SQL常用语句和函数
    NuGet 常用命令
    SQL Server不同服务器不同数据库间的操作
    C# 面试编程算法题
    C# 冒泡排序
    域名和URL各部分组成
  • 原文地址:https://www.cnblogs.com/zhang-Kelly/p/12905572.html
Copyright © 2020-2023  润新知