线段树 --- 单点修改 以及 区间更新中的单点更新

这里说的是单点修改.
模板题
不同于RMQ,RMQ修改后再去处理,复杂度就会很高. 而线段树修改和询问都还是会保持在logn的复杂度之内.

AC Code 和 板子: (求区间最大,最小,区间和稍微修改下就行了, 如果有多种东西(比如说有lazy标记, 或者同时维护多种关系等)要存,直接在结构体中添加相应的元素即可,然后修改一些地方的判断)
//直接用就行了.

const int maxn = 1e6+5;
int n, a[maxn];
struct Tree {
    int tl, tr;
    int minn, maxx;
}tree[maxn<<2];
void pushup(int id) {
    tree[id].minn = min(tree[id<<1].minn , tree[id<<1|1].minn);
    tree[id].maxx = max(tree[id<<1].maxx , tree[id<<1|1].maxx);
}
void build(int id, int l, int r) {
    tree[id].tl = l, tree[id].tr = r;
    if(l == r) {
        tree[id].maxx = tree[id].minn = a[l];
        return ;
    }
    int mid = (r+l)>>1;
    build(id<<1, l, mid);
    build(id<<1|1, mid+1, r);
    pushup(id);
}
void update(int id, int pos, int val) {
    int l = tree[id].tl, r = tree[id].tr;
    if(l == r) {
        tree[id].maxx = tree[id].minn = val;
        return ;
    }
    int mid = (l+r) >> 1;
    if(pos <= mid) update(id<<1, pos, val);
    else update(id<<1|1, pos, val);
    pushup(id);
}
int querymi(int id, int ql, int qr) {
    int l = tree[id].tl, r = tree[id].tr;
    if(ql <= l && r <= qr ){
        return tree[id].minn;
    }
    int mid = (l + r) >> 1;
    if(qr <= mid) return querymi(id<<1, ql, qr);
    else if(ql > mid) return querymi(id<<1|1, ql, qr);
    else return min(querymi(id<<1, ql, mid), querymi(id<<1|1, mid+1, qr));
}
int querymx(int id, int ql, int qr) {
    int l = tree[id].tl, r = tree[id].tr;
    if(ql <= l && r <= qr ){
        return tree[id].maxx;
    }
    int mid = (l + r) >> 1;
    if(qr <= mid) return querymx(id<<1, ql, qr);
    else if(ql > mid) return querymx(id<<1|1, ql, qr);
    else return max(querymx(id<<1, ql, mid), querymx(id<<1|1, mid+1, qr));
}

void solve() {
    scanf("%d",&n);
    for(int i = 1 ; i <= n ; i ++) {
        scanf("%d",&a[i]);
    }
    build(1, 1, n);
    int q; scanf("%d",&q);
    while(q--){
        int op, l, r;
        scanf("%d%d%d",&op, &l, &r);
        if(!op)  printf("%d\n",querymi(1, l, r));  //或者是mx.
        else update(1, l, r);
    }
}

区间更新中的单点更新模板: (该出代码对应的问题) 类似问题 HDU 4027 (区间开根问题, 注意就是输入数据会有l > r的情况).
// 这类题都是套路题, 每个点被修改的次数不会太多次.

const int maxn = 3e5 + 5;
const int maxm = 1e6 + 5;
int cas=1;
int d[maxm];
void init() {
    for (int i = 1 ; i <= 1000000 ; i ++) {
        for (int j = i ; j <= 1000000 ; j += i) {
            d[j]++;
        }
    }
}
ll a[maxn];
struct Tree
{
    int tl, tr; ll val, mx;
}tree[maxn<<2];

void pushup(int id)
{
    tree[id].val = tree[id<<1].val + tree[id<<1|1].val;
    tree[id].mx = max(tree[id<<1].mx, tree[id<<1|1].mx);
}
void build(int id, int l, int r) {
    tree[id].tl = l, tree[id].tr = r;
    if(l == r) {
        tree[id].val = tree[id].mx = a[l];
        return ;
    }
    int mid = (r+l)>>1;
    build(id<<1, l, mid);
    build(id<<1|1, mid+1, r);
    pushup(id);
}

void update(int id, int ul, int ur) {
    int l = tree[id].tl, r = tree[id].tr;
    if (ul <= l && r <= ur && tree[id].mx <= 2) return ;
    // 关键剪枝, 不同的题目这里写的不同, 维护的东西也不同. 由题来定.
    if(l == r){
        tree[id].val = tree[id].mx = d[a[l]];
        a[l] = d[a[l]];
        return ;
    }
    int mid = (l+r) >> 1;
    if (ul <= mid) update(id<<1, ul, ur);
    if (ur > mid) update(id<<1|1, ul, ur);
    pushup(id);
}

ll query(int id, int ql, int qr) {
    int l = tree[id].tl , r = tree[id].tr;
    if(ql <= l && r <= qr) {
        return tree[id].val;
    }
    int mid = (l+r) >> 1 ;
    if(qr <= mid) return query(id<<1, ql, qr);
    else if(ql > mid) return query(id<<1|1, ql, qr);
    else return query(id<<1, ql, mid) + query(id<<1|1, mid+1, qr);
}

void solve() {
    int n, q; init();
    scanf("%d%d",&n, &q);
    for(int i = 1 ; i <= n ; i ++) {
        scanf("%lld", &a[i]);
    }
    build(1, 1, n);
    while(q--){
        int op, l, r;
        scanf("%d%d%d",&op, &l, &r);
        if(op == 1) update(1, l, r);
        else printf("%lld\n", query(1, l, r));
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值