zoukankan      html  css  js  c++  java
  • ACM-线段树

    http://blog.csdn.net/libin56842/article/details/8530197

    基础可以看上面这篇文章

    风格:

    maxn是题目给的最大区间,而节点数要开4倍,确切的说……

    lson和rson辨别表示结点的左孩子和右孩子。

    PushUp(int rt)是把当前结点的信息更新到父节点

    PushDown(int rt)是把当前结点的信息更新给孩子结点。

    rt表示当前子树的根(root),也就是当前所在的结点。

    思想:

    对于每个非叶节点所标示的结点 [a,b],其做孩子表示的区间是[a,(a+b)/2],其右孩子表示[(a+b)/2,b].

    构造:

    离散化和线段树:

    题目:x轴上有若干个线段,求线段覆盖的总长度。

    普通解法:设置坐标范围[min,max],初始化为0,然后每一段分别染色为1,最后统计1的个数,适用于线段数目少,区间范围小。

    离散化的解法:离散化就是一一映射的关系,即将一个大坐标和小坐标进行一一映射,适用于线段数目少,区间范围大。

    例如:[10000,22000],[30300,55000],[44000,60000],[55000,60000].

    第一步:排序 10000 22000 30300 44000 55000 60000

    第二部:编号 1        2        3         4       5         6

    第三部:用编号来代替原数,即小数代大数 。

    [10000,22000]~[1,2]

    [30300,55000]~[3,5]

    [44000,60000]~[4,6]

    [55000,60000]~[5,6]

    然后再用小数进行普通解法的步骤,最后代换回去。

    线段树的解法:线段树通过建立线段,将原来染色O(n)的复杂度减小到 log(n),适用于线段数目多,区间范围小的情况。

    离散化的线段树:适用于线段数目多,区间范围大的情况。

    构造:

    动态数据结构:

    struct node{

     node* left;

     node* right;

    ……

    }

    静态全局数组模拟(完全二叉树):

    struct node{

      int left;

      int right;

    ……

    }Tree[MAXN]

    http://www.xuebuyuan.com/1470670.html

    线段树主要用四种用法

    单点更新:

    模板:

    单点增减,查询线段和

    struct node
    {
        int l,r,c;
    }T[MAXN*4];
    
    void PushUp(int rt)
    {
        T[rt].c = T[rt<<1].c + T[(rt<<1)+1].c;
    }
    
    void build(int l,int r,int x)
    {
        T[x].l = l;
        T[x].r = r;
        T[x].c = 0;
        if (l == r) return;
        int mid = (l+r)>>1;
        build(l,mid,x<<1);
        build(mid+1,r,(x<<1) + 1);
    }
    
    void update(int val,int l,int x)
    {
        if(T[x].l == T[x].r && T[x].l == l)
        {
            T[x].c += val;
            return;
        }
        int mid = (T[x].l + T[x].r)>>1;
        if (l > mid)
        {
            update(val,l,(x<<1) + 1);
        }
        else
        {
            update(val,l,x<<1);
        }
        PushUp(x);
    }
    
    int n,m,ans;
    
    void query(int l,int r,int x)
    {
        if(T[x].l == l && T[x].r == r)
        {
            ans += T[x].c;
            return;
        }
        int mid = (T[x].l + T[x].r)>>1;
        if (l > mid)
        {
            query(l,r,(x<<1)+1);
        }
        else if(r<=mid)
        {
            query(l,r,(x<<1));
        }
        else
        {
            query(l,mid,(x<<1));
            query(mid+1,r,(x<<1)+1);
        }
    }

    HDU 1166

    #include <iostream>
    #include <string>
    #include <cstring>
    #include <cstdlib>
    #include <cstdio>
    #include <cmath>
    #include <algorithm>
    #include <stack>
    #include <queue>
    #include <cctype>
    #include <vector>
    #include <iterator>
    #include <set>
    #include <map>
    #include <sstream>
    using namespace std;
    
    #define mem(a,b) memset(a,b,sizeof(a))
    #define pf printf
    #define sf scanf
    #define spf sprintf
    #define pb push_back
    #define debug printf("!
    ")
    #define MAXN 55555
    #define MAX(a,b) a>b?a:b
    #define blank pf("
    ")
    #define LL long long
    #define ALL(x) x.begin(),x.end()
    #define INS(x) inserter(x,x.begin())
    #define pqueue priority_queue
    #define INF 0x3f3f3f3f
    
    struct node
    {
        int l,r,c;
    }T[MAXN*4];
    
    void PushUp(int rt)
    {
        T[rt].c = T[rt<<1].c + T[(rt<<1)+1].c;
    }
    
    void build(int l,int r,int x)
    {
        T[x].l = l;
        T[x].r = r;
        T[x].c = 0;
        if (l == r) return;
        int mid = (l+r)>>1;
        build(l,mid,x<<1);
        build(mid+1,r,(x<<1) + 1);
    }
    
    void update(int val,int l,int x)
    {
        if(T[x].l == T[x].r && T[x].l == l)
        {
            T[x].c += val;
            return;
        }
        int mid = (T[x].l + T[x].r)>>1;
        if (l > mid)
        {
            update(val,l,(x<<1) + 1);
        }
        else
        {
            update(val,l,x<<1);
        }
        PushUp(x);
    }
    
    int n,m,ans;
    
    void query(int l,int r,int x)
    {
        if(T[x].l == l && T[x].r == r)
        {
            ans += T[x].c;
            return;
        }
        int mid = (T[x].l + T[x].r)>>1;
        if (l > mid)
        {
            query(l,r,(x<<1)+1);
        }
        else if(r<=mid)
        {
            query(l,r,(x<<1));
        }
        else
        {
            query(l,mid,(x<<1));
            query(mid+1,r,(x<<1)+1);
        }
    }
    
    
    int main()
    {
        int t,i,kase=1;
        char d[10];
        sf("%d",&t);
        while(t--)
        {
            mem(T,0);
            pf("Case %d:
    ",kase++);
            sf("%d",&n);
            build(1,n,1);
            for(i=1;i<=n;i++)
            {
                int tmp;
                sf("%d",&tmp);
                update(tmp,i,1);
            }
    
            while (sf("%s",d) != EOF)
            {
                if (d[0] == 'E') break;
                int x, y;
                sf("%d%d", &x, &y);
                if (d[0] == 'Q')
                {
                    ans = 0;
                    query(x,y,1);
                    pf("%d
    ",ans);
                }
                if (d[0] == 'S') update(-y,x,1);
                if (d[0] == 'A') update(y,x,1);
            }
        }
        return 0;
    }

    单点替换,查询线段最高

    模板:

    struct node
    {
        int l,r,c;
    }T[MAXN*4];
    
    void PushUp(int rt)
    {
        T[rt].c = max(T[rt<<1].c,T[(rt<<1)+1].c);
    }
    
    void build(int l,int r,int x)
    {
        T[x].l = l;
        T[x].r = r;
        T[x].c = 0;
        if (l == r) return;
        int mid = (l+r)>>1;
        build(l,mid,x<<1);
        build(mid+1,r,(x<<1) + 1);
    }
    
    void update(int val,int l,int x)
    {
        if(T[x].l == T[x].r && T[x].l == l)
        {
            T[x].c = val;
            return;
        }
        int mid = (T[x].l + T[x].r)>>1;
        if (l > mid)
        {
            update(val,l,(x<<1) + 1);
        }
        else
        {
            update(val,l,x<<1);
        }
        PushUp(x);
    }
    
    int n,m,ans;
    
    void query(int l,int r,int x)
    {
        if(T[x].l == l && T[x].r == r)
        {
            ans = max(ans,T[x].c);
            return;
        }
        int mid = (T[x].l + T[x].r)>>1;
        if (l > mid)
        {
            query(l,r,(x<<1)+1);
        }
        else if(r<=mid)
        {
            query(l,r,(x<<1));
        }
        else
        {
            query(l,mid,(x<<1));
            query(mid+1,r,(x<<1)+1);
        }
    }

    hdu 1754

    这边要注意,输入字符不要用%c,会导致一些难以预料的问题

    #include <iostream>
    #include <string>
    #include <cstring>
    #include <cstdlib>
    #include <cstdio>
    #include <cmath>
    #include <algorithm>
    #include <stack>
    #include <queue>
    #include <cctype>
    #include <vector>
    #include <iterator>
    #include <set>
    #include <map>
    #include <sstream>
    using namespace std;
    
    #define mem(a,b) memset(a,b,sizeof(a))
    #define pf printf
    #define sf scanf
    #define spf sprintf
    #define pb push_back
    #define debug printf("!
    ")
    #define MAXN 200005
    #define MAX(a,b) a>b?a:b
    #define blank pf("
    ")
    #define LL long long
    #define ALL(x) x.begin(),x.end()
    #define INS(x) inserter(x,x.begin())
    #define pqueue priority_queue
    #define INF 0x3f3f3f3f
    
    struct node
    {
        int l,r,c;
    }T[MAXN*4];
    
    void PushUp(int rt)
    {
        T[rt].c = max(T[rt<<1].c,T[(rt<<1)+1].c);
    }
    
    void build(int l,int r,int x)
    {
        T[x].l = l;
        T[x].r = r;
        T[x].c = 0;
        if (l == r) return;
        int mid = (l+r)>>1;
        build(l,mid,x<<1);
        build(mid+1,r,(x<<1) + 1);
    }
    
    void update(int val,int l,int x)
    {
        if(T[x].l == T[x].r && T[x].l == l)
        {
            T[x].c = val;
            return;
        }
        int mid = (T[x].l + T[x].r)>>1;
        if (l > mid)
        {
            update(val,l,(x<<1) + 1);
        }
        else
        {
            update(val,l,x<<1);
        }
        PushUp(x);
    }
    
    int n,m,ans;
    
    void query(int l,int r,int x)
    {
        if(T[x].l == l && T[x].r == r)
        {
            ans = max(ans,T[x].c);
            return;
        }
        int mid = (T[x].l + T[x].r)>>1;
        if (l > mid)
        {
            query(l,r,(x<<1)+1);
        }
        else if(r<=mid)
        {
            query(l,r,(x<<1));
        }
        else
        {
            query(l,mid,(x<<1));
            query(mid+1,r,(x<<1)+1);
        }
    }
    
    
    int main()
    {
        int t,i,kase=1;
        while(sf("%d%d",&n,&m)==2)
        {
            build(1,n,1);
            for(i=1;i<=n;i++)
            {
                int tmp;
                sf("%d",&tmp);
                update(tmp,i,1);
            }
            while (m--)
            {
                int x,y;
                char d[2];
    
                sf("%s %d %d",d,&x, &y);
                //pf("%s %d %d
    ",d,x,y);
                if (d[0] == 'Q')
                {
                    ans = 0;
                    query(x,y,1);
                    pf("%d
    ",ans);
                }
                if (d[0] == 'U') update(y,x,1);
            }
        }
        return 0;
    }

    成段更新

    (通常这对初学者来说是一道坎),需要用到延迟标记(或者说懒惰标记),简单来说就是每次更新的时候不要更新到底,用延迟标记使得更新延迟到下次需要更新or询问到的时候

    http://blog.sina.com.cn/s/blog_a2dce6b30101l8bi.html

    区间替换,求总和

    数组要开4倍才够

    第一种思路,标记

    模板:

    struct node
    {
        int l,r,c,f;
    }T[MAXN<<2];
    
    void PushUp(int rt)
    {
        T[rt].c = T[rt<<1].c + T[(rt<<1)+1].c;
        //pf("%d %d
    ",rt,T[rt].c);
    }
    
    void PushDown(int rt,int m)
    {
        if(T[rt].f)
        {
            T[rt<<1].f = T[(rt<<1) + 1].f = T[rt].f;
            T[rt<<1].c = T[rt].f * (m-(m>>1));
            T[(rt<<1)+1].c = T[rt].f * (m>>1);
            T[rt].f = 0;
        }
    }
    
    void build(int l,int r,int x)
    {
        T[x].l = l;
        T[x].r = r;
        T[x].c = 1;
        T[x].f = 0;
        if (l == r) return;
        int mid = (l+r)>>1;
        build(l,mid,x<<1);
        build(mid+1,r,(x<<1) + 1);
        PushUp(x);
    }
    
    void update(int val,int L,int R,int l,int r,int x)
    {
        if(L <= l && r <= R)
        {
            T[x].f = val;
            T[x].c = val*(r-l+1);
            //pf("%d %d %d
    ",T[x].c,l,r);
            return;
        }
        PushDown(x,r-l+1);
        //pf("%d %d %d %d %d %d
    ",val,L,R,l,r,x);
    
        int mid = (l + r)>>1;
        if (L <= mid)
        {
            update(val,L,R,l,mid,x<<1);
        }
        if(R > mid)
        {
            update(val,L,R,mid+1,r,x<<1|1);
        }
        PushUp(x);
    }

    第二种思路,杂色

    struct node
    {
        int l,r,c;
    }T[MAXN<<2];
    
    void PushUp(int rt)
    {
        T[rt].c = T[rt<<1].c + T[(rt<<1)+1].c;
    }
    
    void PushDown(int rt)
    {
        if(T[rt].c != -1)//如果该区间只有一种颜色
        {
            T[rt<<1].c = T[rt<<1|1].c = T[rt].c;//由于后面必定对子树操作,所以更新子树的值等于父亲的值
            T[rt].c = -1;//由于该区域颜色与修改不同,而且不是给定区域,所以该区域必定为杂色
        }
    }
    
    void build(int l,int r,int x)
    {
        T[x].l = l;
        T[x].r = r;
        T[x].c = 1;
        if (l == r) return;
        int mid = (l+r)>>1;
        build(l,mid,x<<1);
        build(mid+1,r,(x<<1) + 1);
    }
    
    void update(int val,int L,int R,int x)
    {
        if(T[x].c == val) return;//相同则不用修改了
        if(T[x].l == L && T[x].r == R)//找到了区间,直接更新
        {
            T[x].c = val;
            return;
        }
        PushDown(x);
    
        //父区间为杂色时对所有子节点进行操作
        int mid = (T[x].l + T[x].r)>>1;
        if(L>mid)
            update(val,L,R,x<<1|1);
        else if(R<=mid)
            update(val,L,R,x<<1);
        else
        {
            update(val,L,mid,x<<1);
            update(val,mid+1,R,x<<1|1);
        }
    }

    hdu 1698

    http://www.tuicool.com/articles/j6N3eaz

    这里链接的其实不对,要求总和,所以每个点不能初始化为1

    #include <iostream>
    #include <string>
    #include <cstring>
    #include <cstdlib>
    #include <cstdio>
    #include <cmath>
    #include <algorithm>
    #include <stack>
    #include <queue>
    #include <cctype>
    #include <vector>
    #include <iterator>
    #include <set>
    #include <map>
    #include <sstream>
    using namespace std;
    
    #define mem(a,b) memset(a,b,sizeof(a))
    #define pf printf
    #define sf scanf
    #define spf sprintf
    #define pb push_back
    #define debug printf("!
    ")
    #define MAXN 100000 + 5
    #define MAX(a,b) a>b?a:b
    #define blank pf("
    ")
    #define LL long long
    #define ALL(x) x.begin(),x.end()
    #define INS(x) inserter(x,x.begin())
    #define pqueue priority_queue
    #define INF 0x3f3f3f3f
    
    struct node
    {
        int l,r,c,f;
    }T[MAXN<<2];
    
    void PushUp(int rt)
    {
        T[rt].c = T[rt<<1].c + T[(rt<<1)+1].c;
        //pf("%d %d
    ",rt,T[rt].c);
    }
    
    void PushDown(int rt,int m)
    {
        if(T[rt].f)
        {
            T[rt<<1].f = T[(rt<<1) + 1].f = T[rt].f;
            T[rt<<1].c = T[rt].f * (m-(m>>1));
            T[(rt<<1)+1].c = T[rt].f * (m>>1);
            T[rt].f = 0;
        }
    }
    
    void build(int l,int r,int x)
    {
        T[x].l = l;
        T[x].r = r;
        T[x].c = 1;
        T[x].f = 0;
        if (l == r) return;
        int mid = (l+r)>>1;
        build(l,mid,x<<1);
        build(mid+1,r,(x<<1) + 1);
        PushUp(x);
    }
    
    void update(int val,int L,int R,int l,int r,int x)
    {
        if(L <= l && r <= R)
        {
            T[x].f = val;
            T[x].c = val*(r-l+1);
            //pf("%d %d %d
    ",T[x].c,l,r);
            return;
        }
        PushDown(x,r-l+1);
        //pf("%d %d %d %d %d %d
    ",val,L,R,l,r,x);
    
        int mid = (l + r)>>1;
        if (L <= mid)
        {
            update(val,L,R,l,mid,x<<1);
        }
        if(R > mid)
        {
            update(val,L,R,mid+1,r,x<<1|1);
        }
        PushUp(x);
    }
    
    int n,m,ans;
    
    void query(int l,int r,int x)
    {
        if(T[x].l == l && T[x].r == r)
        {
            ans += T[x].c;
            return;
        }
        int mid = (T[x].l + T[x].r)>>1;
        if (l > mid)
        {
            query(l,r,(x<<1)+1);
        }
        else if(r<=mid)
        {
            query(l,r,(x<<1));
        }
        else
        {
            query(l,mid,(x<<1));
            query(mid+1,r,(x<<1)+1);
        }
    }
    
    int a[MAXN];
    
    
    int main()
    {
        int t,i,kase=1;
        sf("%d",&t);
        while(t--)
        {
            sf("%d",&n);
            build(1,n,1);
            sf("%d",&m);
            for(i=1;i<=m;i++)
            {
                int x,y,z;
                sf("%d%d%d",&x,&y,&z);
                update(z,x,y,1,n,1);
            }
            pf("Case %d: The total value of the hook is %d.
    ",kase++,T[1].c);
        }
        return 0;
    }

    区间增减,区间求和

    模板:

    struct node
    {
        LL l,r,c,f;
    }T[MAXN<<2];
    
    void PushUp(int rt)
    {
        T[rt].c = T[rt<<1].c + T[(rt<<1)+1].c;
        //pf("%d %d
    ",rt,T[rt].c);
    }
    
    void PushDown(int rt,int m)
    {
        if(T[rt].f)
        {
            T[rt<<1].f += T[rt].f;
            T[(rt<<1) + 1].f += T[rt].f;
            T[rt<<1].c += T[rt].f * (m-(m>>1));
            T[(rt<<1)+1].c += T[rt].f * (m>>1);
            T[rt].f = 0;
        }
    }
    
    void build(int l,int r,int x)
    {
        T[x].l = l;
        T[x].r = r;
        T[x].f = 0;
        T[x].c = 0;
        if(l==r) return;
        int mid = (l+r)>>1;
        build(l,mid,x<<1);
        build(mid+1,r,(x<<1) + 1);
    }
    
    void update(int val,int L,int R,int l,int r,int x)
    {
        if(L <= l && r <= R)
        {
            T[x].f += val;
            T[x].c += val*(r-l+1);
            //pf("%d %d %d
    ",T[x].c,l,r);
            return;
        }
        PushDown(x,r-l+1);
        //pf("%d %d %d %d %d %d
    ",val,L,R,l,r,x);
    
        int mid = (l + r)>>1;
        if (L <= mid)
        {
            update(val,L,R,l,mid,x<<1);
        }
        if(R > mid)
        {
            update(val,L,R,mid+1,r,x<<1|1);
        }
        PushUp(x);
    }
    
    LL ans;
    
    int n,m;
    
    void query(int L,int R,int l,int r,int x)
    {
        if(L <= l && r <= R)
        {
            ans += T[x].c;
            return;
        }
        PushDown(x,r-l+1);
        int mid = (l + r)>>1;
        if(L <= mid) query(L,R,l,mid,x<<1);
        if(R > mid) query(L,R,mid+1,r,x<<1|1);
        PushUp(x);
    }

    poj 3468

    #include <iostream>
    #include <string>
    #include <cstring>
    #include <cstdlib>
    #include <cstdio>
    #include <cmath>
    #include <algorithm>
    #include <stack>
    #include <queue>
    #include <cctype>
    #include <vector>
    #include <iterator>
    #include <set>
    #include <map>
    #include <sstream>
    using namespace std;
    
    #define mem(a,b) memset(a,b,sizeof(a))
    #define pf printf
    #define sf scanf
    #define spf sprintf
    #define pb push_back
    #define debug printf("!
    ")
    #define MAXN 111111 + 5
    #define MAX(a,b) a>b?a:b
    #define blank pf("
    ")
    #define LL long long
    #define ALL(x) x.begin(),x.end()
    #define INS(x) inserter(x,x.begin())
    #define pqueue priority_queue
    #define INF 0x3f3f3f3f
    
    struct node
    {
        LL l,r,c,f;
    }T[MAXN<<2];
    
    void PushUp(int rt)
    {
        T[rt].c = T[rt<<1].c + T[(rt<<1)+1].c;
        //pf("%d %d
    ",rt,T[rt].c);
    }
    
    void PushDown(int rt,int m)
    {
        if(T[rt].f)
        {
            T[rt<<1].f += T[rt].f;
            T[(rt<<1) + 1].f += T[rt].f;
            T[rt<<1].c += T[rt].f * (m-(m>>1));
            T[(rt<<1)+1].c += T[rt].f * (m>>1);
            T[rt].f = 0;
        }
    }
    
    void build(int l,int r,int x)
    {
        T[x].l = l;
        T[x].r = r;
        T[x].f = 0;
        if(l==r)
        {
            scanf("%I64d",&T[x].c);
            return;
        }
        int mid = (l+r)>>1;
        build(l,mid,x<<1);
        build(mid+1,r,(x<<1) + 1);
        PushUp(x);
    }
    
    void update(int val,int L,int R,int l,int r,int x)
    {
        if(L <= l && r <= R)
        {
            T[x].f += val;
            T[x].c += val*(r-l+1);
            //pf("%d %d %d
    ",T[x].c,l,r);
            return;
        }
        PushDown(x,r-l+1);
        //pf("%d %d %d %d %d %d
    ",val,L,R,l,r,x);
    
        int mid = (l + r)>>1;
        if (L <= mid)
        {
            update(val,L,R,l,mid,x<<1);
        }
        if(R > mid)
        {
            update(val,L,R,mid+1,r,x<<1|1);
        }
        PushUp(x);
    }
    
    LL ans;
    
    int n,m;
    
    void query(int L,int R,int l,int r,int x)
    {
        if(L <= l && r <= R)
        {
            ans += T[x].c;
            return;
        }
        PushDown(x,r-l+1);
        int mid = (l + r)>>1;
        if(L <= mid) query(L,R,l,mid,x<<1);
        if(R > mid) query(L,R,mid+1,r,x<<1|1);
    }
    
    
    int main()
    {
        int t,i,kase=1;
        while(~sf("%d%d",&n,&m))
        {
            build(1,n,1);
            /*
            for(i=1;i<=n;i++)
            {
                int tmp;
                sf("%d",&tmp);
                update(tmp,i,i,1,n,1);
            }
            */
            for(i=1;i<=m;i++)
            {
                int x,y,z;
                char s[2];
                sf("%s",s);
                if(s[0]=='Q')
                {
                    ans = 0;
                    sf("%d%d",&x,&y);
                    query(x,y,1,n,1);
                    pf("%I64d
    ",ans);
                }
                else
                {
                    sf("%d%d%d",&x,&y,&z);
                    update(z,x,y,1,n,1);
                }
            }
        }
        return 0;
    }
  • 相关阅读:
    Eclipse启动Tomcat报错,系统缺少本地apr库
    Linux(Debian)下Maven的安装
    Debian ls 文件 文件夹颜色显示
    Mybatis3.0防止SQL注入
    MySql初始配置
    文档在线预览开源实现方案一:OpenOffice + SwfTools + FlexPaper
    Java多线程的信号量
    判断线程池中的线程是否全部执行完毕
    一个简单的死锁
    使用并发来提高数据抓取的效率
  • 原文地址:https://www.cnblogs.com/qlky/p/5690265.html
Copyright © 2011-2022 走看看