线段树小结

线段树(Interval Tree)

实际上还是称为区间树更好理解一些。
树:是一棵树,而且是一棵二叉树。
线段:树上的每个节点对应于一个线段(还是叫“区间”更容易理解,区间的起点和终点通常为整数)
同一层的节点所代表的区间,相互不会重叠。同一层节点所代表的区间,加起来是个连续的区间。

叶子节点的区间是单位长度,不能再分了。

线段树的深度不超过log2(n)+1(向上取整,n是根节点对应区间的长度)。

线段树上,任意一个区间被分解后得到的“终止节点”数目都是log(n)量级。

线段树上更新叶子节点和进行区间分解时间复杂度都是O(log(n))的。


这些结论为线段树能在O(log(n))的时间内完成插入数据,更新数据、查找、统计等工作,提供了理论依据。


非叶子节点可以放和,最值,类型,状态,空间容量(一般用于离散化之后)。

1.结构体定义

struct node
{
	int left,right;
	int w;
	int mid()
	{
		return (left+right)/2;
	}
}node[max*3];   //max视情况而定
关于max,
有时需要进行离散化处理,一般是qsort后开一个很大的数组储存i++,进行映射;
有时候可能并不是题目给的那个明显的n,而是需要输入update的个数;  例如杭电2795;
总而言之,这一切的目的都是把max减到最小;


2.建树

void build(int i,int l,int r)
{
	node[i].left=l;node[i].right=r;
	node[i].w=0;     //对节点node[i]初始化;
	if(l==r)       //这里可以对叶子节点进行附值;
	   return ;    //也可以用一个father数组记录每个node[i].left的i;
	build(i*2,l,(l+r)/2);
	build(i*2+1,(l+r)/2+1,r);
}


3.更新

void update(int i,int l,int r,int c)   
{
	if(node[i].left==l&&node[i].right==r)
		node[i].w+=c;
	if(node[i].mid()>=r) update(i*2,l,r,c);
	else if(node[i].mid()<l) update(i*2+1,l,r,c);
	else
	{
		update(i*2,l,node[i].mid(),c);
		update(i*2+1,node[i]+1,r,c);
	}
}


build和update以void格式时都有一个回溯功能,可以用起来减少步骤;例如build用于区域求和;update用于区段的更新;
if(node[i+i].w&&node[i+i+1].w) node[i].w=1;
不要一更新就更新到叶子节点,那样更新效率最坏就可能变成O(n)的了!有些甚至要把信息全部累计在非叶子节点,最后从某个叶子节点返回上去进行统计;



4.查找

int query(int i,int l,int r)
{
	if(node[i].left==l&&node[i].right==r) return node[i].w;
	if(node[i].mid()>=r) return query(i*2,l,r);
	else if(node[i].mid()<l) return query(i*2+1,l,r);
	else return query(i*2,l,node[i].mid())+query(i*2+1,node[i].mid()+1,l);
}

5.其他

有些关于先后问题例如排队poj2828,覆盖poj2825,可以先从后而前考虑,因为后面的都是可以确定的;


当给你的某个值n比较小的时候,可能是给你遍历的可能性;

线段树还有区间合并和lazy标记需要拓展。

当然很多难题关于线段树和其他知识点(例如数论)的结合就只能凭能力了。

下面网址有点资料还不错。

http://acm.pku.edu.cn/summerschool/pku_acm_train.htm


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值