zoukankan      html  css  js  c++  java
  • HDU

    题意:给出两个序列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;
                }
            }
        }
    }
  • 相关阅读:
    什么是多线程中的上下文切换?
    什么是基本表?什么是视图?
    什么是存储过程?用什么来调用?
    随意写文件命令?怎么向屏幕输出带空格的字符串,比如” hello world”?
    NULL 是什么意思 ?
    Mock 或 Stub 有什么区别?
    什么叫视图?游标是什么?
    什么是微服务中的反应性扩展?
    什么是线程组,为什么在 Java 中不推荐使用?
    Java 中用到的线程调度算法是什么?
  • 原文地址:https://www.cnblogs.com/Tianwell/p/11325890.html
Copyright © 2011-2022 走看看