数据结构——线段树

未完成—2017.2.22号

问:在以数组结构描述线段树的数据结构下,如果原区间的大小为n,为什么线段树的数组需要分配4*n的空间?
线段树的特点:
1.任意节点的左右子树是共同存在的
2.任意节点的左右子树的叶子节点的差的绝对值小于等于1
3.任意节点的左右子树的高度差|HH|1

注:满足上述条件的树必满足下面两条类似的说法:
1.如果除去线段树的最后一层的节点,那么余下的节点为完全二叉树
2.如果将倒数第二层的所有叶子节点都补上左右子树(区间为0),那么该树为完全二叉树。

证明:根据以上条件,如图所示为区间大小为5的线段树结构,其所需要的数据空间最大。
这里写图片描述

假设节点数为n;
H1=log2(n1)+1
H=log2(n1)+2
故节点个数为:
nodes=2H1=2log2(n1)+21=4(n1)1=4n5
故线段树的节点个数一般为其范围的4倍。

单点更新

/*
 ============================================================================
 Name        : enemysoldiers.c
 Author      : selous
 Version     :
 Copyright   : Your copyright notice
 Description : enemy soldiers;segment tree;
 ============================================================================
 */
/*features:
 * 1.节点不记录*/
#include <stdio.h>
#include <stdlib.h>
#define maxind 6

/*[BEGIN,END] is section of segment tree*/
#define BEGIN 1
#define END 5

int array[maxind];
int segTree[maxind*4];

/*build the segment tree*/
void build(int node,int begin,int end){

    if(begin==end){
        segTree[node] = array[begin];
    }else{
        /*recurse build left and right subtree*/
        build(2*node,begin,(begin+end)/2);
        build(2*node+1,(begin+end)/2+1,end);

        /*when recall,calculate father node information*/
        segTree[node] = segTree[2*node]+segTree[2*node+1];
    }
}

/*query giving interval information*/

int query(int node,int begin,int end,int left,int right){

    /*start with first node*/
    int p1;
    int p2;
    /*No intersection*/
    if(begin>right||end<left){
        return 0;
    }
    /*  if the current interval is included in  */
    /*  the query interval return segTree[node]  */
    if(begin>=left&&end<=right){
        return segTree[node];
    }

    /*according order of building*/
    p1 = query(2 * node, begin, (begin + end) / 2, left, right);
    p2 = query(2 * node + 1, (begin + end) / 2 + 1, end, left, right);


    /*return query value;*/
    return p1+p2;
}

/*update the single node information */
/*the section is [begin,end]*/
void update(int node,int begin,int end,int position,int change){

    if(begin==end){
        segTree[node]+=change;
    }else{
        int mid;
        mid = (begin+end) >>1;
        if(mid>position) update(2*node,begin,mid,position,change);
        else update(2*node+1,mid+1,end,position,change);
        /*single node change*/
        /*recall,father node need to change*/
        segTree[node]+=change;
    }

}

int main() {

    int i;
    for(i=0;i<maxind;i++){
        array[i]=i;
    }

    build(1,BEGIN,END);
    update(1,BEGIN,END,5,-5);
    int num = query(1,BEGIN,END,1,5);

    printf("num of emery:%d",num);
    return 0;
}

离散化

成端更新

//============================================================================
// Name        : segmentTree.cpp
// Author      : selous
// Version     :
// Copyright   : Your copyright notice
// Description : segment tree;segment update;lazy method;
//============================================================================


/*whether update or query function,we should not change the section [left,right]*/


/*start from the root node,dichotomy the tree like when building*/
#include <iostream>
using namespace std;

typedef struct Node{

    int right,left;
    int sum;
    int add;
    int mid(){return (right+left)>>1;}

}node;

#define LC(node) node<<1 /*represented left child*/
#define RC(node) (node<<1)+1/*represent right child*/
const int maxind = 400; /*max section*/
int array[maxind];
node nodes[maxind<<2];/*number of nodes*/

void pushUp(int node){
    nodes[node].sum = nodes[LC(node)].sum+nodes[RC(node)].sum;
}

/*has a tag in the node*/
/*[nodes.left,nodes.right]<=[left,right]*/
void pushDown(int node){

    if(nodes[node].add){

        nodes[LC(node)].add+=nodes[node].add;
        nodes[RC(node)].add+=nodes[node].add;

        /*更新左右节点的值*/
        nodes[LC(node)].sum+=nodes[node].add*(nodes[LC(node)].right-nodes[LC(node)].left+1);
        nodes[RC(node)].sum+=nodes[node].add*(nodes[RC(node)].right-nodes[RC(node)].left+1);

        /*delete the tag*/
        nodes[node].add=0;
    }
}


/*rt represent present node number*/
void build(int rt,int begin,int end){
    nodes[rt].left=begin;
    nodes[rt].right=end;
    /*leaf node*/
    if(begin==end){
        nodes[rt].add=0;
        nodes[rt].sum = array[begin];
    /*father node*/
    }else{
        build(LC(rt),begin,nodes[rt].mid());
        build(RC(rt),nodes[rt].mid()+1,end);

        /*recall*/
        pushUp(rt);
        nodes[rt].add=0;
    }
}

/*[left right] the section that need to update */
void update(int rt,int left,int right,int num){

    if(left<=nodes[rt].left&&right>=nodes[rt].right){

        nodes[rt].sum += (nodes[rt].right-nodes[rt].left+1) * num;
        nodes[rt].add += num;
        return;
    }

//  pushDown(rt);

    int m = nodes[rt].mid();

    /*update the right child tree*/
    if(right>m) update(RC(rt),left,right,num);
    /*update the left child tree*/
    if(left<=m) update(LC(rt),left,right,num);

    /*calculate the father node*/
    pushUp(rt);
}

/*only when query,we should invoke the pushDown function*/
int query(int node,int left,int right){

    /*[nodes.left,nodes.right]<=[left,right]*/
    if(nodes[node].left>=left&&nodes[node].right<=right){
        return nodes[node].sum;
    }

    /*if the node has tag,pushdown to its child*/
    pushDown(node);

    int p1=0,p2=0;
    int m = nodes[node].mid();
    if(left<=m)p1=query(LC(node),left,right);

    if(right>m)p2=query(RC(node),left,right);

    return p1+p2;
}

int main() {


    for(int i=1;i<5;i++){
        array[i]=i;
    }
    build(1,1,4);
    update(1,2,3,3);
    update(1,1,2,2);
    update(1,1,2,3);
//  cout<<query(1,2,3)<<endl;

    for(int i=1;i<20;i++){
        cout<<nodes[i].left<<" "<<nodes[i].right<<" "<<nodes[i].sum<<endl;
    }
    return 0;
}

区间合并

//============================================================================
// Name        : villageProblem.cpp
// Author      : selous
// Version     :
// Copyright   : Your copyright notice
// Description : Hello World in C++, Ansi-style
//============================================================================

#include <iostream>
using namespace std;
const int maxNum=50;

#define Lc(c) c<<1
#define Rc(c) (c<<1)+1
typedef struct Node{
    int left,right;//[left,right] section
    int lseg;//left max continue segment
    int rseg;
    int mseg;//max continuous segment
}node;

node nodes[maxNum];

int array[maxNum];


/*calculate father node information with his child nodes.*/
void pushUp(int i){

    nodes[i].lseg=nodes[Lc(i)].lseg;//left continuous segment
    nodes[i].rseg=nodes[Rc(i)].rseg;//right continuous segment
    nodes[i].mseg=max(max(nodes[Lc(i)].mseg,nodes[Rc(i)].mseg),
            nodes[Lc(i)].rseg+nodes[Rc(i)].lseg);
    /*all in the Lc(i) is empty*/
    if(nodes[Lc(i)].lseg==nodes[Lc(i)].right-nodes[Lc(i)].left+1){
        nodes[i].lseg+=nodes[Rc(i)].lseg;
    }
    /*all in the Rc(i) is empty*/
    if(nodes[Rc(i)].rseg==nodes[Rc(i)].right-nodes[Rc(i)].left+1){
        nodes[i].rseg+=nodes[Lc(i)].rseg;
    }

}

/*build segment tree;initial*/
void build(int start,int begin,int end){

    nodes[start].left=begin;
    nodes[start].right=end;
    nodes[start].lseg=nodes[start].rseg=nodes[start].mseg=end-begin+1;
    if(begin==end){
        return;
    }
    int mid = (begin+end)>>1;
    /*build the left child tree*/
    build(Lc(start),begin,mid);
    /*build the right child tree*/
    build(Rc(start),mid+1,end);
}


/*update single node information*/
void update(int start,int node,int t){

    if(nodes[start].left==nodes[start].right){
        /*t equals 1 means rebuild the village*/
        /*t equals 0 means destroy the village*/
        nodes[start].lseg=nodes[start].rseg=nodes[start].mseg=t;
        return;
    }


    /**/
    int mid = (nodes[start].right+nodes[start].left)>>1;

    if(mid<node){
        update(Rc(start),node,t);
    }else{
        update(Lc(start),node,t);
    }

    pushUp(start);
}

/*query max village section include the ith village*/
int query(int start,int i){
    /*1.node start is a leaf node*/
    /*2.max empty segment is 0 or equal to the size of the segment*/
    if(nodes[start].left==nodes[start].right||
            nodes[start].mseg==0||
            nodes[start].mseg==nodes[start].left-nodes[start].right+1){
        return nodes[start].mseg;
    }

    /*the middle of the node start section*/
    int mid = (nodes[start].left+nodes[start].right)>>1;

    /*if ith locate in the right child tree*/
    if(mid<i){
        if(i<=nodes[Rc(start)].left+nodes[Rc(start)].lseg-1){
            return query(Rc(start),i)+query(Lc(start),mid);
        }else{
            return query(Rc(start),i);
        }

    }else{
        /*i is located in right section*/
        if(i>=nodes[Lc(start)].right-nodes[Lc(start)].rseg+1){
            return query(Lc(start),i)+query(Rc(start),mid+1);
            //return nodes[Lc(start)].rseg+nodes[Rc(start)].lseg;
        }else{
            return query(Lc(start),i);
        }
    }
}


int main() {

    int i;
    for(i=1;i<=10;i++){
        array[i]=i;
    }

    build(1,1,10);
    update(1,4,0);
    update(1,6,0);
    update(1,8,0);
    update(1,6,1);
    for(int i=1;i<=20;i++){
    cout<<i<<":"<<nodes[i].left<<" "<<nodes[i].right<<" "<<nodes[i].lseg
            <<" "<<nodes[i].rseg<<" "<<nodes[i].mseg<<endl;
    }
    cout<<query(1,5)<<endl;
    return 0;
}

扫描线

//============================================================================
// Name        : Rectangular.cpp
// Author      : selous
// Version     :
// Copyright   : Your copyright notice
// Description : Rectangular Area;Rectangle;scanning line
//============================================================================

#include <iostream>
#include<algorithm>
using namespace std;
#define Lc(node) node<<1
#define Rc(node) (node<<1)+1
const int MAXNUM = 50;
/*一次扫描过程就是一次update的过程*/
/*一条下位边就是一个扫描线*/
typedef struct node{
    double sum;//node[1].sum记录扫描线结果的长度。
    int cnt;//记录该线段是否是下位线
}Node;//node of segment tree
typedef struct edge{
    double left;//value of edge's left x1;
    double right;//value of edge's right x2;
    double height;//value of edge's distance relative to x-axes
    int cnt;//上位线1,下位线-1
    edge(){left=right=height=cnt=0;}
    edge(double l,double r,double h,double c){
        left=l;
        right=r;
        height=h;
        cnt=c;
    }
    bool operator < (const edge &edge)const{
        return height<edge.height;
    }
}edge;
edge edges[MAXNUM];
double X[MAXNUM];//储存所有长方形的X坐标
node nodes[MAXNUM<<2];
void pushUp(int root){
    /*如果左右子节点的左右子树的cnt不相同*/
    if(nodes[Lc(root)].cnt==-1||nodes[Rc(root)].cnt==-1){
        nodes[root].cnt=-1;
    /*如果左右子节点的cnt不相同*/
    }else if(nodes[Lc(root)].cnt!=nodes[Rc(root)].cnt){
        nodes[root].cnt=-1;
    }else{
        nodes[root].cnt=nodes[Lc(root)].cnt;//左右子树的任意一个节点值
    }
    //向上推,的sum为左右节点和nodes[root].sum=nodes[Lc(root)].sum+nodes[Rc(root)].sum;
}
void pushDown(int root,int left,int right){
    int m = (left+right)>>1;
    //左右节点的cnt相同,能推下去
    if(nodes[root].cnt!=-1){
        //三个的cnt是相同的    nodes[Rc(root)].cnt=nodes[Lc(root)].cnt=nodes[root].cnt;    nodes[Lc(root)].sum=nodes[Lc(root)].cnt?X[m+1]-X[left]:0;       nodes[Rc(root)].sum=nodes[Rc(root)].cnt?X[right+1]-X[m+1]:0;
    }
}
void build(int root,int begin,int end){
    if(begin == end){
        nodes[root].cnt=0;
        nodes[root].sum=0;
    }
    int mid = (begin+end) >> 1;
    build(Lc(root),begin,mid);
    build(Rc(root),mid+1,end);
    pushUp(root);
}
/*segment update*/
/*[left,right]区间更新值为value*/
/*[begin,end]为root根节点所在的区间*/
void update(int left,int right,int value,int root,int begin,int end){
    if(left<=begin&&right>=end){
        if(nodes[root].cnt!=-1){
            nodes[root].cnt+=value;
            /*如果cnt!=0,为区间之长度*/
            /*如果cnt为0,则该长度不计入总长度*/
            nodes[root].sum=(nodes[root].cnt?X[right+1]-X[left]:0);
        }
    }
    pushDown(root,begin,end);
    int m = (begin+end)>>1;
    if(left<=m) update(left,right,value,Lc(root),begin,m);
    if(right>m) update(left,right,value,Rc(root),m+1,end);
    pushUp(root);
}

int main() {
    int q;//number of rectangle
    cin>>q;
    double x1,x2,y1,y2;
    int i;
    int n=0;//number of edges;
    for(i=0;i<q;i++){
        cin>>x1>>y1>>x2>>y2;
        n++;
        X[n]=x1;
        edges[n]=edge(x1,x2,y1,1);//下位边为1
        n++;
        X[n]=x2;
        edges[n]=edge(x1,x2,y2,-1);//上位边为-1
    }
    sort(X+1,X+n+1);
    sort(edges+1,edges+n+1);
    for(i=1;i<=n;i++){
        cout<<X[i]<<" ";
    }
    //去除X中的重复元素
    int k=1;
    for(i=2;i<=n;i++){
        if(X[i]!=X[i-1]){X[++k]=X[i];}
    }
    //建树
    build(1,1,k-1);

    //求面积
    double square = 0.0;
    cout<<"square of the rectangle is"<<square<<endl;
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值