线段树研究了三天了!!!第一天理解了线段树是如何操作数据的,但是不太理解线段树的离散化,不知道离散化是用来干嘛的。第二天又研究了好久离散化,才知道其核心!……
其实离散化还是挺容易理解的,比如求一些线段的重合,给出一些线段,如:(2,4),(4,8),(6,8);如果没离散化就建树的话,最大的数是8,那么树就为build(1,8),即最大的上限为8。如果离散化,把这几个数排下序:2,4,6,8;那么分别让2指向1,4指向2,6指向3,8指向4,即1代表2,2代表4,3代表6,4代表8,然后树就为build(1,4),即最大的上限为4,比未离散化之前省了4个量级,树比之前的树就少了很久节点了,即可以省内存,又把时间给节约了,这就是压缩法,即离散化。
刚开始我离散化之前没有排序,然后结果出错,搞了好久才知道要排序,晕……离散化之后求就比较方便了。因为如果ACM题目出的上限为10^9,那么不离散化之前,你肯定要建的树为build(1,10^9),离散化之后看情况建的树,这样就比较好了。比如下面的离散化方法:
map<int,int>q;
int p[M],w[M],j=0,n,m,i,c[M],d[M];
scanf("%d%d",&n,&m);
for(i=0;i<n;i++)
{
scanf("%d%d",&c[i],&d[i]);
w[j++]=c[i];
w[j++]=d[i];
}
for(i=0;i<m;i++)
{
scanf("%d",&p[i]);
w[j++]=p[i];
}
sort(w,w+j); //先排序,因为去重的时候用得到
int ans=unique(w,w+j)-w; //unique为C++自带的去重函数,ans为去重后的数组的下标上限
build(1,1,ans);
for(i=0;i<ans;i++)
q[w[i]]=i+1;
for(i=0;i<n;i++)
update(1,q[c[i]],q[d[i]]);
lazy思想:我理解和会用离散化之后,又遇到问题了,因为我提交代码的时候TLE了,后面看了别人的代码进行比较,看到别人有:tree[i].lazy,不知道这个是干嘛用的,百度了一下,才知道是用来标记的。就是如果我输入线段(4,8),那么没标记之前,对(4,8)以下的所有左儿子和右儿子都直接加上重复的值了,就是更新树的时候,这条线段以下的所有结点都要更新,而在实际中,这条线段以下的结点可能不会用得到,那么更新这些结点是没有用的,所以在建树的时候顺便加上一个tree[i].lazy,在这条线段的这个结点那,标记这个结点以下要更新的值,即加上或者乘上的值,即tree[i].lazy=value,然后在需要这个结点以下的时候再计算以下的结点就得了,如果不需要,那当然不用计算下面的了。
这个代码就不用给了,百度上好多代码,忘的时候再看别人的吧!
终于把线段树的每个知道点都学会了,现在运用去咯!!!刷几道题巩固一下…………