线段树模板

摘抄自http://www.notonlysuccess.com/index.php/segment-tree-complete/

  • maxn是题目给的最大区间,而节点数要开4倍,确切的来说节点数要开大于maxn的最小2x的两倍
  • lson和rson分辨表示结点的左儿子和右儿子,由于每次传参数的时候都固定是这几个变量,所以可以用预定于比较方便的表示
  • 以前的写法是另外开两个个数组记录每个结点所表示的区间,其实这个区间不必保存,一边算一边传下去就行,只需要写函数的时候多两个参数,结合lson和rson的预定义可以很方便
  • PushUP(int rt)是把当前结点的信息更新到父结点
  • PushDown(int rt)是把当前结点的信息更新给儿子结点
  • rt表示当前子树的根(root),也就是当前所在的结点
  • #define lson l , m , rt << 1
    
    #define rson m + 1 , r , rt << 1 | 1
    
     
    
    const int maxn = 55555;
    
    int lsum[maxn<<2] , rsum[maxn<<2] , msum[maxn<<2];
    
    int cover[maxn<<2];
    
     
    
    void PushDown(int rt,int m) {
    
        if (cover[rt] != -1) {
    
            cover[rt<<1] = cover[rt<<1|1] = cover[rt];
    
            msum[rt<<1] = lsum[rt<<1] = rsum[rt<<1] = cover[rt] ? 0 : m - (m >> 1);
    
            msum[rt<<1|1] = lsum[rt<<1|1] = rsum[rt<<1|1] = cover[rt] ? 0 : (m >> 1);
    
            cover[rt] = -1;
    
        }
    
    }
    
    void PushUp(int rt,int m) {
    
        lsum[rt] = lsum[rt<<1];
    
        rsum[rt] = rsum[rt<<1|1];
    
        if (lsum[rt] == m - (m >> 1)) lsum[rt] += lsum[rt<<1|1];
    
        if (rsum[rt] == (m >> 1)) rsum[rt] += rsum[rt<<1];
    
        msum[rt] = max(lsum[rt<<1|1] + rsum[rt<<1] , max(msum[rt<<1] , msum[rt<<1|1]));
    
    }
    
    void build(int l,int r,int rt) {
    
        msum[rt] = lsum[rt] = rsum[rt] = r - l + 1;
    
        cover[rt] = -1;
    
        if (l == r) return ;
    
        int m = (l + r) >> 1;
    
        build(lson);
    
        build(rson);
    
    }
    
    void update(int L,int R,int c,int l,int r,int rt) {
    
        if (L <= l && r <= R) {
    
            msum[rt] = lsum[rt] = rsum[rt] = c ? 0 : r - l + 1;
    
            cover[rt] = c;
    
            return ;
    
        }
    
        PushDown(rt , r - l + 1);
    
        int m = (l + r) >> 1;
    
        if (L <= m) update(L , R , c , lson);
    
        if (m < R) update(L , R , c , rson);
    
        PushUp(rt , r - l + 1);
    
    }
    
    int query(int w,int l,int r,int rt) {
    
        if (l == r) return l;
    
        PushDown(rt , r - l + 1);
    
        int m = (l + r) >> 1;
    
        if (msum[rt<<1] >= w) return query(w , lson);
    
        else if (rsum[rt<<1] + lsum[rt<<1|1] >= w) return m - rsum[rt<<1] + 1;
    
        return query(w , rson);
    
    }

     

你可能感兴趣的:(线段树)