zoukankan      html  css  js  c++  java
  • 多段树状数组

    固定总长的多棵树状数组

    概述

    有时候,我们需要很多棵树状数组,每棵尺寸的值域都很大,但总长是固定的并且不太大。

    此时我们可以将所有树状数组顺序放在一个数组上面,将询问离线后给每棵树状数组标一个起点和尺寸,每次从起点开始按照正常的二进制位做即可。

    一般形式

    先直接给出伪代码

    inline void update(int *树状数组起点,int 树状数组尺寸,int 询问位置,int 更新值){
        while(下标<=尺寸){
            进行更新,
            下标加上lowbit
        }
    }
    
    inline void update(int *树状数组起点,int 树状数组尺寸,int 询问位置){
        while(下标不为零){
            统计贡献
            下标减去lowbit
        }
    }
    

    调用

    update(树状数组+起点[i],尺寸[i],位置,值)
    printf(query(树状数组+起点[i],尺寸[i],位置))
    

    可以看到,和普通的树状数组几乎一样,因为拆分后的部分数组符合树状数组所有的性质。

    例题

    [P3960 列队](%3Ca href="https://www.luogu.org/problem/P3960"%3Ehttps://www.luogu.org/problem/P3960%3C/a%3E)

    这道题抽象后需要维护(N)行中的(Q)个区间,需要构造(N)个数组支持二分查找每一个区间,这时候我们可以将区间按照行数编号排序,建一棵长度为(Q)的树状数组,然后用上面的方法对于每行建立树状数组,复杂的二分查找查找也可以进行。

    inline void update(LL *ar,int siz,int x,LL c){
    	while(x<=siz){
    		ar[x]+=c;
    		x+=x&(-x);
    	}
    }
    inline int query(LL *ar,int siz,int x){
    	/*binary search*/
    	int l=1,r,mid,sum,ret;
    	while(l<=siz&&ar[l]<x){
    		l<<=1;
    		ret=l;
    	}
    	r=l;
    	sum=ar[(l>>=1)];
    	while(l<r-1){
    		mid=(l+r)>>1;
    		if(mid>siz||ar[mid]+sum>=x){
    			r=mid;
    			ret=mid;
    		}else{
    			l=mid;
    			sum+=ar[l];
    		}
    	}
    	ret=r;
    	return ret;
    }
    
  • 相关阅读:
    audio元素
    获取页面中出现次数最多的三个标签以及出现次数
    vue ssr(server side rendering)
    python_2 python的编码声明
    python_1 python的编译过程
    bugs
    isPrototypeOf和 instanceof 的区别
    WebStorm 配置Git
    MongoDB 副本集搭建
    获取结算样式 getComputedStyle-currentStyle
  • 原文地址:https://www.cnblogs.com/guoshaoyang/p/11315592.html
Copyright © 2011-2022 走看看