势能线段树

势能线段树

1.算法分析

本文章目的主要是为了留个区间取max/min的模板,代码参考:https://oi-wiki.org/ds/seg-beats/#hdu5306-gorgeous-sequence

2.典型例题

2.1 区间与t取min/询问区间max

HDU5306 Gorgeous Sequence

题意: 维护一个长度为n(1e5)的序列a,进行如下的1e5次操作:

0 l r t:将[l, r]内的元素与t取min,a[i] = min(a[i], t)

1 l r t:输出[l, r]中的最大值

2 l r:输出[l, r]区间和

**题解: ** 本题取区间min,然后询问最大值;如果我取区间max,询问最小值,只需要在建树的时候全部取负号即可。

代码:

#include <bits/stdc++.h>

using namespace std;
const int N = 1e6 + 6;

char nc() {
   
    static char buf[1000000], *p = buf, *q = buf;
    return p == q && (q = (p = buf) + fread(buf, 1, 1000000, stdin), p == q)
               ? EOF
               : *p++;
}
int rd() {
   
    int res = 0;
    char c = nc();
    while (!isdigit(c)) c = nc();
    while (isdigit(c)) res = res * 10 + c - '0', c = nc();
    return res;
}

int t, n, m;
int a[N];  // 1e6个数字
int mx[N << 2], se[N << 2], cn[N << 2], tag[N << 2];
long long sum[N << 2];

inline void pushup(int u) {
     // 向上更新标记
    const int ls = u << 1, rs = u << 1 | 1;
    sum[u] = sum[ls] + sum[rs];
    if (mx[ls] == mx[rs]) {
   
        mx[u] = mx[rs];
        se[u] = max(se[ls], se[rs]);
        cn[u] = cn[ls] + cn[rs];
    } else if (mx[ls] > mx[rs]) {
   
        mx[u] = mx[ls];
        se[u] = max(se[ls], mx[rs]);
        cn[u] = cn[ls];
    } else {
   
        mx[u] = mx[rs];
        se[u] = max(mx[ls], se[rs]);
        cn[u] = cn[rs];
    }
}

inline void pushtag(int u, int tg) {
     // 单纯地打标记,不暴搜
    if (mx[u] <= tg) return;
    sum[u] += (1ll * tg - mx[u]) * cn[u];
    mx[u] = tag[u] = tg;
}

inline void pushdown(int u) {
   
    if (tag[u] == -1) return;
    pushtag(u << 1, tag[u]), pushtag(u << 1 | 1, tag[u]);
    tag[u] = -1;
}

void build(int u = 1, int l = 1, int r = n) {
   
    tag[u] = -1;
    if (l == r) {
   
        sum[u] = mx[u] = a[l], se[u] = -1, cn[u] = 1;
        return;
    }
    int mid = (l + r) >> 1;
    build(u << 1, l, mid), build(u << 1 | 1, mid + 1, r);
    pushup(u);
}

void modify_min(int L, int R, int v, int u = 1, int l = 1, int r = n) {
   
    if (mx[u] <= v) return;
    if (L <= l && r <= R && se[u] < v) return pushtag(u, v);
    int mid = (l + r) >> 1
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值