线段树

来源:互联网 发布:javascript 数组去重 编辑:程序博客网 时间:2024/06/08 03:07
线段树是一个用一个数组,想象一棵完全二叉树,赋予其一些意义,数组中存储的信息即为每个节点

数组中的0 是不用的。

 

#define MAX 10000  //待处理的点数,不是树中的节点数int tree[MAX * 4];void build(int t, int l, int r){    if (l == r)    {        //cin>>tree[t];        //tree[t]=0;        //对叶子初始化        return;    }    int mid = l + r >> 1;    build(t << 1, l, mid);    build(t << 1 | 1, mid + 1, r);    //tree[t] = tree[t << 1] + tree[t << 1 | 1];    //tree[t] = max(tree[t << 1], tree[t << 1 | 1]);    //对儿子节点递归完可以再用当前点的儿子更新当前点}//----------------------------------------------------------------------void point_update(int t, int l, int r,int x,int y)//将a[x]改为y,点更新{    if (l == r)    {        //tree[t] = y;        return;    }    int mid = l + r >> 1;    if (x <= mid)        //x在左边        point_update(t << 1, l, mid, x, y);//继续将xy传参    else if (x > mid)    //x在右边        point_update(t << 1 | 1, mid + 1, r, x, y);    //tree[t] = tree[t << 1] + tree[t << 1 | 1];    //tree[t] = max(tree[t << 1], tree[t << 1 | 1]);    //对儿子节点递归完可以再用当前点的儿子更新当前点}//-----------------------------------------------------------------------------------------int ans;void query(int t, int l, int r, int x, int y)//询问[x,y]的某东西,如最大值。区间查询,需要一个全局变量{    if (x <= l&&y >= r) //当前区间属于[x,y]    {        //ans += tree[t];        return;    }    int mid = l + r >> 1;    if (y <= mid)        //y<=mid说明整个查询区间都在左边        query(t << 1, l, mid, x, y);//继续将xy传参    else if (x > mid)    //x>mid说明整个查询区间都在右边        query(t << 1 | 1, mid + 1, r, x, y);    else                //区间跨过mid ,则分别往左右儿子递归    {        query(t << 1, l, mid, x, y);        query(t << 1 | 1, mid + 1, r, x, y);    }}//-------------------------------------------------------------------------//区间更新还需要记录下每个节点打的标记struct node{    int num;    int flag;}tre[MAX*4];void interval_update(int t, int l, int r, int x, int y,int z)//[x,y]内的数都加z{    if (x <= l&&y >= r) //当前区间属于[x,y],不用再往下走,直接在这里打标记    {        tre[t].flag += z;        return;    }    int mid = l + r >> 1;    if (y <= mid)        //y<=mid说明整个查询区间都在左边        interval_update(t << 1, l, mid, x, y,z);//继续将xy传参    else if (x > mid)    //x>mid说明整个查询区间都在右边        interval_update(t << 1 | 1, mid + 1, r, x, y,z);    else                //区间跨过mid ,则分别往左右儿子递归    {        interval_update(t << 1, l, mid, x, y,z);        interval_update(t << 1 | 1, mid + 1, r, x, y,z);    }}void travel(int t, int l, int r, int f)//f为当前点所以祖先的flag之和{    if (l == r)    {        tre[t].num += f;        tre[t].num += tre[t].flag;//应加上所有祖先的flag和自己的        return;    }    int mid = l + r >> 1;    travel(t << 1, l, mid,f+tre[t].flag);    travel(t << 1 | 1, mid + 1, r,f+tre[t].flag);    //tree[t] = tre[t << 1].num + tre[t << 1 | 1].num;    //tree[t] = max(tre[t << 1].num, tre[t << 1 | 1].num);    //对儿子节点递归完可以再用当前点的儿子更新当前点}