HDU - 6315 Naive Operations (线段树)

题意:给出两个序列a,b;a序列一开始为0,b序列为输入中给出的固定序列
有n次修改,l r k ,即在a的(l,r)区间内的元素全部加1。
在m次查询,l r 即询问在区间以内 的值
思路:区间修改已经区间维护就会想到线段树。但是怎样维护这棵树?由于b是固定的序列,且ai/bi还要向下取整
我们区间要修改即是 某个ai+1之后成为bi的倍数。但是仍不好判断,a的区间倒是修改了,但是ai/bi的取值还是要搜寻到
每个叶子结点去。 所以我们换一种 写法,ai+1同样可以表示为bi-1,当某个bi变为0了即ai就增加到这个bi的倍数去了
然后我们把这个bi又重置会原来的值,这样区间就可以维护了
我们开一个Min数组记录之前对bi修改后的状态最小值,如果该值为0,则说明这个区间就会使sum发生改变,那么我们在递归下去
找到Min[p] = 0的位置进行修改即可

#include <cstdio>
#include <cstring>
#include <iostream>
#include <cmath>
#include <algorithm>
#define ll long long
#define IOS ios::sync_with_stdio(0); cin.tie(0);using namespace std;
using namespace std; 
const int maxn = 1e5+1;
int Min[maxn<<2];//存储区间最小
ll sum[maxn<<2];//存储区间和
ll lazy[maxn<<2];
int arr[maxn];
int b[maxn];
void push_up(int p){
    sum[p] = sum[p<<1] + sum[p<<1|1];
    Min[p] = min(Min[p<<1],Min[p<<1|1]);
}

void push_down(int k) {
    if (lazy[k]) {
        lazy[k << 1] += lazy[k];
        lazy[k << 1 | 1] += lazy[k];
        Min[k << 1] -= lazy[k];
        Min[k << 1 | 1] -= lazy[k];
        lazy[k] = 0;
    }
}

void build(int p,int l,int r){
    sum[p] = lazy[p] = 0;
    if(l==r) {
        Min[p] = b[l];
        return ;
    }
    int mid = (l+r)>>1;
    build(p<<1,l,mid);
    build(p<<1|1,mid+1,r);
    push_up(p);
}
//void dfs(int p,int l,int r){
//    if(Min[p] != 0) return ;
//    if(l == r){
//        sum[p]++; Min[p] = b[l];
//        return ;
//    }
//    push_down(p);
//    int mid = (l+r)>>1;
//    if(Min[p<<1] == 0) dfs(p<<1,l,mid);
//    if(Min[p<<1|1] == 0) dfs(p<<1|1,mid+1,r);
//    push_up(p);
//}

void dfs(int rt, int l, int r) {
    if(Min[rt] != 0)    return ;
    if(l == r) {
        sum[rt]++, Min[rt] = b[l];
        return ;
    }
    push_down(rt);
    int mid = l+r>>1;
    if(Min[rt<<1] == 0)
        dfs(rt<<1, l, mid);
    if(Min[rt<<1|1] == 0)
        dfs(rt<<1|1, mid+1, r);
    push_up(rt);
}
void update(int p ,int l,int r,int L,int R){
    int mid = (l+r)>>1;
    if(L<=l&&r<=R){
        Min[p]--;
        lazy[p] += 1;
        if(Min[p]==0){
            dfs(p,l,r);       
        }
        return;
    }
    push_down(p);
    if(L<=mid) update(p<<1,l,mid,L,R);
    if(R>mid) update(p<<1|1,mid+1,r,L,R);
    push_up(p);
}

int query(int p,int l,int r,int ql,int qr){
    int res = 0;
    if(ql<=l && r<=qr){
        return sum[p];
    }
    push_down(p);
    int mid = (l+r)>>1;
    if(ql<=mid) res += query(p<<1,l,mid,ql,qr);  
    if(qr>mid) res += query(p<<1|1,mid+1,r,ql,qr);
    return res;
}
int main(){
    IOS;
    int n,m;
    string s;
    while(cin>>n>>m){
        int L,R;
        for(int i = 1;i<=n;i++){
            cin>>b[i];//线段树默认从1开始记录
        }
        build(1,1,n);
        for(int i = 0;i<m;i++){
            cin>>s;
            if(s[0]=='a'){
                cin>>L>>R;
                update(1,1,n,L,R);
            }else{
                cin>>L>>R;
                cout<<query(1,1,n,L,R)<<endl;
            }
        }
    }
}

 

posted @ 2019-08-09 11:02  Tianwell  阅读(171)  评论(0)    收藏  举报