序列 [线段树]

序 列 序列

在这里插入图片描述


正 解 部 分 \color{red}{正解部分}

使用 线段树 维护 b b b, 初值为 − b i -b_i bi, 每次修改时, 若一个位置上的值变为了 0 0 0, 则说明其会对答案产生新的贡献,
在外部使用 树状数组 将贡献计入答案, 然后将该位置的值 重置为 − b i -b_i bi, 重置的时间复杂度是 O ( log ⁡ N ) O(\log N) O(logN) .

考虑最坏情况, 每次操作 [ 1 , N ] [1, N] [1,N],
这样 b i = 1 b_i=1 bi=1 的位置最多重置 N N N b i = 2 b_i=2 bi=2 最多重置 N 2 \frac{N}{2} 2N 次, b i = 3 b_i=3 bi=3 最多 …

所以总共需要 重置 O ( N log ⁡ N ) O(N \log N) O(NlogN) 次, 总时间复杂度 O ( N log ⁡ 2 N ) O(N \log^2 N) O(Nlog2N) .


实 现 部 分 \color{red}{实现部分}

重置 可以在 修改 时 使用 u p d a t e ( ) update() update() 实现 .

#include<bits/stdc++.h>
#define reg register
#define fi first
#define se second
typedef std::pair<int, int> pr;

int read(){
        char c;
        int s = 0, flag = 1;
        while((c=getchar()) && !isdigit(c))
                if(c == '-'){ flag = -1, c = getchar(); break ; }
        while(isdigit(c)) s = s*10 + c-'0', c = getchar();
        return s * flag;
}

const int maxn = 100005;
const int inf = 0x3f3f3f3f;

int N;
int M;
int Tmp_1;
int B[maxn];

struct Bit_Tree{
        int v[maxn], lim;
        void Add(int k, int x){ while(k<=lim)v[k]+=x,k+=k&-k; }
        int Query(int k){ if(k<=0)return 0; int s=0; while(k)s+=v[k],k-=k&-k; return s; }
} bit_t;

struct Segment_Tree{

        struct Node{ int l, r, t, max_v, id; } T[maxn << 2];

        void Push_down(const int &k){ 
                T[k].max_v += T[k].t;
                if(T[k].l == T[k].r) return T[k].t = 0, void();
                T[k<<1].t += T[k].t, T[k<<1|1].t += T[k].t, T[k].t = 0;
        }

        void Push_up(const int &k){
                if(T[k<<1].t) Push_down(k<<1);
                if(T[k<<1|1].t) Push_down(k<<1|1);
                T[k].max_v = std::max(T[k<<1].max_v, T[k<<1|1].max_v); 
                if(T[k<<1].max_v == T[k].max_v) T[k].id = k<<1;
                else T[k].id = k<<1|1;
        }

        void Build(int k, int l, int r){
                T[k].l = l, T[k].r = r; if(l == r) return T[k].max_v = B[l], T[k].id = k, void();
                int mid = l+r >> 1; Build(k<<1, l, mid), Build(k<<1|1, mid+1, r); Push_up(k);
        }

        void update(int k){
                int l = T[k].l, r = T[k].r;
                if(T[k].t) Push_down(k);
                if(l == r) return bit_t.Add(l, 1), T[k].max_v=B[l], void();
                update(T[k].id); Push_up(k);
        }

        void Modify(int k, const int &ql, const int &qr, const int &aim){
                int l = T[k].l, r = T[k].r;
                if(T[k].t) Push_down(k);
                if(r < ql || l > qr) return ;
                if(ql <= l && r <= qr){
                        T[k].t += aim, Push_down(k); 
                        while(!T[k].max_v) update(k);
                        return ;
                }
                Modify(k<<1, ql, qr, aim), Modify(k<<1|1, ql, qr, aim); Push_up(k);
        }

        int Query(int k, const int &ql, const int &qr){
                int l = T[k].l, r = T[k].r;
                if(T[k].t) Push_down(k);
                if(r < ql || l > qr) return -inf;
                if(ql <= l && r <= qr) return T[k].max_v;
                return std::max(Query(k<<1, ql, qr), Query(k<<1|1, ql, qr));
        }

} seg_t;

int main(){
        N = read(), M = read();
        for(reg int i = 1; i <= N; i ++) B[i] = -read();
        seg_t.Build(1, 1, N); bit_t.lim = N;
        for(reg int i = 1; i <= M; i ++){
                int opt = read(), l = read(), r = read();
                if(opt == 2) printf("%d\n", bit_t.Query(r) - bit_t.Query(l-1));
                else seg_t.Modify(1, l, r, 1);
        }
        return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值