未完成—2017.2.22号
问:在以数组结构描述线段树的数据结构下,如果原区间的大小为n,为什么线段树的数组需要分配4*n的空间?
线段树的特点:
1.任意节点的左右子树是共同存在的
2.任意节点的左右子树的叶子节点的差的绝对值小于等于1
3.任意节点的左右子树的高度差|H左−H右|≤1
注:满足上述条件的树必满足下面两条类似的说法:
1.如果除去线段树的最后一层的节点,那么余下的节点为完全二叉树
2.如果将倒数第二层的所有叶子节点都补上左右子树(区间为0),那么该树为完全二叉树。
证明:根据以上条件,如图所示为区间大小为5的线段树结构,其所需要的数据空间最大。
假设节点数为n;
H−1=log2(n−1)+1
H=log2(n−1)+2
故节点个数为:
nodes=2H−1=2log2(n−1)+2−1=4(n−1)−1=4n−5
故线段树的节点个数一般为其范围的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;
}