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("!\n")
#define MAXN 55555
#define MAX(a,b) a>b?a:b
#define blank pf("\n")
#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:\n",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\n",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("!\n")
#define MAXN 200005
#define MAX(a,b) a>b?a:b
#define blank pf("\n")
#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\n",d,x,y);
            if (d[0] == 'Q')
            {
                ans = 0;
                query(x,y,1);
                pf("%d\n",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\n",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\n",T[x].c,l,r);
        return;
    }
    PushDown(x,r-l+1);
    //pf("%d %d %d %d %d %d\n",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("!\n")
#define MAXN 100000 + 5
#define MAX(a,b) a>b?a:b
#define blank pf("\n")
#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\n",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\n",T[x].c,l,r);
        return;
    }
    PushDown(x,r-l+1);
    //pf("%d %d %d %d %d %d\n",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.\n",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\n",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\n",T[x].c,l,r);
        return;
    }
    PushDown(x,r-l+1);
    //pf("%d %d %d %d %d %d\n",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("!\n")
#define MAXN 111111 + 5
#define MAX(a,b) a>b?a:b
#define blank pf("\n")
#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\n",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\n",T[x].c,l,r);
        return;
    }
    PushDown(x,r-l+1);
    //pf("%d %d %d %d %d %d\n",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\n",ans);
            }
            else
            {
                sf("%d%d%d",&x,&y,&z);
                update(z,x,y,1,n,1);
            }
        }
    }
    return 0;
}

 

posted @ 2016-07-21 02:10  qlky  阅读(1139)  评论(0编辑  收藏  举报