zoukankan      html  css  js  c++  java
  • 线段树再整理、

    代码和思路来自:传送门

    建树模板、

    // 一:线段树基本概念
    //1:概述
    //线段树,类似区间树,是一个完全二叉树,它在各个节点保存一条线段(数组中的一段子数组),
    //主要用于高效解决连续区间的动态查询问题,由于二叉结构的特性,它基本能保持每个操作的复杂度为O(lgN)!
    //性质:父亲的区间是[a,b],(c=(a+b)/2)左儿子的区间是[a,c],右儿子的区间是[c+1,b],线段树需要的空间为数组大小的四倍 #include<iostream> using namespace std; const int qq=256; int segtree[(qq<<2)+10]; int array[qq]; void build(int node,int l,int r) { if(l==r) segtree[node]=array[l]; else{ build(node<<1,l,(l+r)/2); build((node<<1)+1,(l+r)/2+1,r); if(segtree[node<<1]<=segtree[(node<<1)+1]) segtree[node]=segtree[node<<1]; else segtree[node]=segtree[(node<<1)+1]; } } int main() { array[0]=1,array[1]=2,array[2]=2,array[3]=4,array[4]=1,array[5]=3; build(1,0,5); for(int i=1;i<=20;++i) cout << "Seg" << i << "=" << segtree[i] << endl; return 0; } //此模板用于查询区间最小值、

    对应查询函数模板、

    //区间查询int query(int node, int begin, int end, int left, int right);
    //(其中node为当前查询节点,begin,end为当前节点存储的区间,left,right为此次query所要查询的区间)
    //主要思想是把所要查询的区间[a,b]划分为线段树上的节点,然后将这些节点代表的区间合并起来得到所需信息
    //比如前面一个图中所示的树,如果询问区间是[0,2],或者询问的区间是[3,3],不难直接找到对应的节点回答这一问题。但并不是所有的提问都这么容易回答,
    int query(int node,int begin,int end,int l,int r)
    {                                // l,r 为所要查找的区间、 
        int p1,p2;
        if(l>end||r<begin)    //查询区间和所给区间完全没有交集、 
            return -1;
        if(begin>=l && end<=r)
            return segtree[node];
        p1=query(node<<1,l,(begin+end)>>1,l,r);
        p2=query((node<<1)+1,((begin+end)>>1)+1,end,l,r);
        if(p1==-1)    return p2;
        if(p2==-1)    return p1;
        if(p1<=p2)    return p1;
        else        return p2;
    } 
    //可见,这样的过程一定选出了尽量少的区间,它们相连后正好涵盖了整个[left,right],没有重复也没有遗漏。
    //同时,考虑到线段树上每层的节点最多会被选取2个,一共选取的节点数也是O(log n)的,因此查询的时间复杂度也是O(log n)。
    //线段树并不适合所有区间查询情况,它的使用条件是“相邻的区间的信息可以被合并成两个区间的并区间的信息”。即问题是可以被分解解决的。

    对应单点更新模板、

    void updata(int node,int l,int r,int ind,int add)    //单结点更新、
    {
        if(l==r){
            segtree[node]+=add;
            return ;
        }
        int m = (l+r) >> 1
        if(ind<=m)    updata(node<<1,l,m,ind,add);
        else        updata((node<<1)+1,m+1,r,ind,add);
        segtree[node]=min(segtree[node<<1],segtree[(node<<1)+1]);
    }
    //回溯的时候修改每个结点的最小值、 

    RMQ 查询区间最值下标、

    #include<iostream> 
    #include<cstring>     
    using namespace std;      
    #define MAXN 100    
    #define MAXIND 256 //线段树节点个数    
    //构建线段树,目的:得到M数组.    
    void build(int node, int b, int e, int M[], int A[])    
    {    
        if (b == e)    
            M[node] = b; //只有一个元素,只有一个下标    
        else{     
            build(2 * node, b, (b + e) / 2, M, A);    
            build(2 * node + 1, (b + e) / 2 + 1, e, M, A);    
            if (A[M[2 * node]] <= A[M[2 * node + 1]])    
                M[node] = M[2 * node];    
            else    
                M[node] = M[2 * node + 1];    
        }    
    }     
    //找出区间 [i, j] 上的最小值的索引    
    int query(int node, int b, int e, int M[], int A[], int i, int j)    
    {    
        int p1, p2; 
        //查询区间和要求的区间没有交集    
        if (i > e || j < b)        return -1; 
        if (b >= i && e <= j)    return M[node];     
        p1 = query(2 * node, b, (b + e) / 2, M, A, i, j);    
        p2 = query(2 * node + 1, (b + e) / 2 + 1, e, M, A, i, j);    
        //return the position where the overall    
        //minimum is    
        if (p1 == -1)    return M[node] = p2;    
        if (p2 == -1)    return M[node] = p1;    
        if (A[p1] <= A[p2])        return M[node] = p1;
        else                    return M[node] = p2;
        // M[node]中记录的是该节点的索引、 
    }    
    int main()
    {    
        int M[MAXIND]; //下标1起才有意义,否则不是二叉树,保存下标编号节点对应区间最小值的下标.    
        memset(M,-1,sizeof(M));    
        int a[]={3,4,5,7,2,1,0,3,4,5};    
        build(1, 0, sizeof(a)/sizeof(a[0])-1, M, a);    
        cout<<query(1, 0, sizeof(a)/sizeof(a[0])-1, M, a, 0, 5)<<endl;    
        return 0;    
    }    

    连续区间修改或单结点更新的动态查询问题

    #include <cstdio>    
    #include <algorithm>    
    using namespace std;
    #define lson l , m , rt << 1    
    #define rson m + 1 , r , rt << 1 | 1   
    #define root 1 , N , 1   
    #define LL long long    
    const int maxn = 111111;    
    LL add[maxn<<2];    
    LL sum[maxn<<2];    
    void PushUp(int rt) {    
        sum[rt] = sum[rt<<1] + sum[rt<<1|1];    
    }    
    void PushDown(int rt,int m) {    
        if (add[rt]) {    
            add[rt<<1] += add[rt];    
            add[rt<<1|1] += add[rt];    
            sum[rt<<1] += add[rt] * (m - (m >> 1));    
            sum[rt<<1|1] += add[rt] * (m >> 1);    
            add[rt] = 0;    
        }    
    }    
    void build(int l,int r,int rt) {    
        add[rt] = 0;    
        if (l == r) {    
            scanf("%lld",&sum[rt]);    
            return ;    
        }    
        int m = (l + r) >> 1;    
        build(lson);    
        build(rson);    
        PushUp(rt);    
    }    
    void update(int L,int R,int c,int l,int r,int rt) {    
        if (L <= l && r <= R) {    
            add[rt] += c;    
            sum[rt] += (LL)c * (r - l + 1);    
            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);    
    }    
    LL query(int L,int R,int l,int r,int rt) {    
        if (L <= l && r <= R) {    
            return sum[rt];    
        }    
        PushDown(rt , r - l + 1);    
        int m = (l + r) >> 1;    
        LL ret = 0;    
        if (L <= m) ret += query(L , R , lson);    
        if (m < R) ret += query(L , R , rson);    
        return ret;    
    }    
    int main() {    
        int N , Q;    
        scanf("%d%d",&N,&Q);    
        build(root);    
        while (Q --) {    
            char op[2];    
            int a , b , c;    
            scanf("%s",op);    
            if (op[0] == 'Q') {    
                scanf("%d%d",&a,&b);    
                printf("%lld
    ",query(a , b ,root));    
            } else {    
                scanf("%d%d%d",&a,&b,&c);    
                update(a , b , c , root);    
            }    
        }    
        return 0;    
    }
  • 相关阅读:
    sqlserver中判断表或临时表是否存在
    Delphi 简单方法搜索定位TreeView项
    hdu 2010 水仙花数
    hdu 1061 Rightmost Digit
    hdu 2041 超级楼梯
    hdu 2012 素数判定
    hdu 1425 sort
    hdu 1071 The area
    hdu 1005 Number Sequence
    hdu 1021 Fibonacci Again
  • 原文地址:https://www.cnblogs.com/sasuke-/p/5333452.html
Copyright © 2011-2022 走看看