ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

hdu5306 Gorgeous Sequence - 吉老师线段树 区间取min操作

2021-04-13 14:35:23  阅读:285  来源: 互联网

标签:cnt min int rson Sequence sum Gorgeous mx se


传送门

  • [l,r] 区间,把大于x的变成x
  • 求区间最大值
  • 求区间和

普通线段树不能做到区间取min操作,但是吉老师提出了一个方法传送门
在普通线段树基础上,每个结点维护的值有sum表示区间和,mx表示区间最大值,cnt表示区间最大值出现的次数,se表示区间次大值

其核心想法在于

  1. 当 \(m a \leq x\) 时,显然这一次修改不会对这个节点产生影响,直接退出。
  2. 当se \(<x<m a\) 时,显然这一次修改只会影响到所有最大值,所以我们 把num加上cnt \(\cdot(x-m a)\), 把 \(m a\) 更新为 \(x\) ,接看打上标记然后退出。
  3. 当se \(\geq x\) 时,我们无法直接更新这一个节点的信息,因此在这时,我们对
    当前节点的左儿子与右儿子进行递归搜索。

特点在于没有去用lazy标记,而是直接利用左右孩子区间的最大值和整个区间的最大值比较来判断整整个区间是否要进行变化。

#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int N = 1e6 + 5;
int a[N];
struct Segment_Tree{
    struct Node {
        int l, r, mx, se, cnt; // 区间最大值mx, 区间次大值se, 区间最大值个数cnt
        ll sum;
        #define l(p) tree[p].l
        #define r(p) tree[p].r
        #define mx(p) tree[p].mx
        #define se(p) tree[p].se
        #define cnt(p) tree[p].cnt
        #define sum(p) tree[p].sum
        #define lson (p << 1)
        #define rson (p << 1 | 1)
    } tree[N << 2];
    void pushup(int p) {
        sum(p) = sum(lson) + sum(rson); // 所有sum都是这样的
        mx(p) = max(mx(lson), mx(rson)); // 所有max都是这样
        cnt(p) = 0;
        if(mx(lson) == mx(rson)) {
            cnt(p) = cnt(lson) + cnt(rson);
            se(p) = max(se(lson), se(rson));
        }else {
            if(mx(lson) > mx(rson)) {
                cnt(p) = cnt(lson);
                se(p) = max(se(lson), mx(rson));
            } else {
                cnt(p) = cnt(rson);
                se(p) = max(se(rson), mx(lson));
            }
        }
    }
    void pushdown(int p) {
        if(mx(lson) > mx(p)) {
            sum(lson) -= 1ll * (mx(lson) - mx(p)) * cnt(lson);
            mx(lson) = mx(p);
        }
        if(mx(rson) > mx(p)) {
            sum(rson) -= 1ll * (mx(rson) - mx(p)) * cnt(rson);
            mx(rson) = mx(p);
        }
    }
    void build(int p, int l, int r){
        l(p) = l, r(p) = r, mx(p) = cnt(p) = sum(p) = 0;
        se(p) = -1;
        if(l == r) {
            sum(p) = mx(p) = a[l]; 
            se(p) = -1; cnt(p) = 1;
            return ;
        }
        int mid = (l + r) >> 1;
        build(lson, l, mid); build(rson, mid + 1, r);
        pushup(p);
    }
    void Change_min(int p, int l, int r, int x){ // [l,r] a[i] = min(a[i], x);
        if(mx(p) <= x) return;
        if(l <= l(p) && r(p) <= r && se(p) < x) {
            sum(p) -= 1ll * (mx(p) - x) * cnt(p);
            mx(p) = x;
            return;
        }
        pushdown(p);
        int mid = (l(p) + r(p)) >> 1;
        if(l <= mid) Change_min(lson, l, r, x);
        if(r > mid) Change_min(rson, l, r, x);
        pushup(p);
    }
    int Query_max(int p, int l, int r) {
        if(l <= l(p) && r(p) <= r) return mx(p);
        pushdown(p);
        int mid = (l(p) + r(p)) >> 1;
        int ans = 0;
        if(l <= mid) ans = max(ans, Query_max(lson, l, r)); 
        if(r > mid) ans = max(ans, Query_max(rson, l, r));
        return ans;
    }
    ll Query_sum(int p, int l, int r) {
        if(l <= l(p) && r(p) <= r) return sum(p);
        pushdown(p);
        int mid = (l(p) + r(p)) >> 1;
        ll ans = 0;
        if(l <= mid) ans += Query_sum(lson, l, r); 
        if(r > mid) ans += Query_sum(rson, l, r);
        return ans;
    }
} seg;
void solve(){
    int n, m; scanf("%d%d", &n, &m);
    for(int i = 1; i <= n; i++) scanf("%d", &a[i]);
    seg.build(1, 1, n);
    for(int i = 1; i <= m; i++) {
        int op, l, r, x;
        scanf("%d%d%d", &op, &l, &r);
        if(op == 0) {
            scanf("%d", &x); seg.Change_min(1, l, r, x);
        }
        if(op == 1) printf("%d\n", seg.Query_max(1, l, r));
        if(op == 2) printf("%lld\n", seg.Query_sum(1, l, r));
    }
}
int main(){
    int t; scanf("%d", &t);
    for(int i = 1; i <= t; i++) solve();
    return 0;
}

标签:cnt,min,int,rson,Sequence,sum,Gorgeous,mx,se
来源: https://www.cnblogs.com/Emcikem/p/14653042.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有