您的位置:首页 > 其它

线段树模板

2017-04-07 19:16 197 查看
点更新与区间查询

#include<iostream>
#include<cstdio>
#include<algorithm>
usingnamespacestd;
constintmaxn=200010;

structnode
{
intmark;
intmax;
}stu[4*maxn];

voidbuild(intl,intr,inti)//i为结构体数组的下标
{
stu[i].max=0;//给每个节点赋初值
if(l==r){
scanf("%d",&stu[i].mark);
stu[i].max=stu[i].mark;//当最后线段等于点的时候赋初值。最底层!!,递归结束,一层一层的结束
return;
}
intmid=(l+r)/2;
build(l,mid,i<<1);//zuo
build(mid+1,r,(i<<1)+1);//you

stu[i].max=max(stu[i<<1].max,stu[(i<<1)+1].max);//递归,顾名思义就是自下而上,不断地从下往上更新答案,最后退出的肯定是根节点i=1
}

voidupdate(intl,intr,inti,intx,inty)//i数组下标,x待查数据下标,y待查数据的变化量
{
if(l==r){//说明不断二分找到了x,就是l==r==x;
stu[i].mark=y;
stu[i].max=stu[i].mark;
return;
}
intmid=(l+r)/2;//找到中间
if(x<=mid)
update(l,mid,i<<1,x,y);
else
update(mid+1,r,(i<<1)+1,x,y);

stu[i].max=max(stu[i<<1].max,stu[(i<<1)+1].max);
}

intquerymax(intl,intr,inti,intx,inty)//区间查询
{
if(x<=l&&y>=r)returnstu[i].max;//如果覆盖就选择区间内的最大值

intmid=(l+r)/2;//这个地方要注意,要把x,y分开与mid比较,这样就可以通过不断地递归,将左右两端都求解出来
intMax=0;
if(x<=mid)//如果x在左,这是一种特殊情况,y不能确定,但是x不在左,那x肯定在右,y也必定在右
Max=max(Max,querymax(l,mid,i<<1,x,y));
if(y>mid)
Max=max(Max,querymax(mid+1,r,(i<<1)+1,x,y));

returnMax;
}


区间更新模板(用到了懒惰标记,区间更新是线段树的核心,只能最大最小值的线段树)

#include<iostream>
#include<cstdio>
usingnamespacestd;
constintmaxn=10000;
structnode
{
intval;
intadd;//延迟标记
}segTree[4*maxn];

voidpushdown(inti)
{
if(segTree[i].add!=0){
//先向下传递标记
segTree[i<<1].add+=segTree[i].add;//设置左右孩子为标志域,孩子节点可能被多次延迟标记又没有向下传递
segTree[(i<<1)+1].add+=segTree[i].add;
//将标记赋给子节点
segTree[i<<1].val+=segTree[i].add;
segTree[(i<<1)+1].val+=segTree[i].add;
//将标记清零
segTree[i].add=0;
}
}
voidbuild(inti,intl,intr)
{
segTree[i].add=0;//设置延迟标记域
if(l==r){
scanf("%d",&segTree[i].val);
return;
}
intmid=(l+r)>>1;
build(i<<1,l,mid);
build((i<<1)+1,mid+1,r);

segTree[i].val=max(segTree[i<<1].val,segTree[(i<<1)+1].val);
}
//点更新
voidupdate1(inti,intl,intr,intx,inty)//x是被更新的位置,y是增量,点更新
{
if(l==r){
segTree[i].val+=y;
return;
}
intmid=(l+r)>>1;
if(x<=mid)
update1(i<<1,l,mid,x,y);
else
update1((i<<1)+1,mid+1,r,x,y);

segTree[i].val=max(segTree[i<<1].val,segTree[(i<<1)+1].val);

}
//区间更新
voidupdate(inti,intl,intr,intx,inty,intaddval)//i下标,lr左右,xy所选区间,addval增量
{
if(y<l||x>r)return;
if(x<=l&&y>=r){
segTree[i].add+=addval;//最低端加标记
segTree[i].val+=addval;//赋值标记,
return;
}
pushdown(i);//自下而上更新区间上的懒惰标记
intmid=(l+r)/2;
update(i<<1,l,mid,x,y,addval);
update((i<<1)+1,mid+1,r,x,y,addval);

segTree[i].val=max(segTree[i<<1].val,segTree[(i<<1)+1].val);//不断的判断更新标记。
}
intquerymax(inti,intl,intr,intx,inty)//被查询的区间
{
if(x<=l&&y>=r)returnsegTree[i].val;
intmid=(l+r)>>1;
pushdown(i);//延时标记域向下传递
intMax=0;
if(x<=mid)
Max=max(Max,querymax(i<<1,l,mid,x,y));
if(y>mid)
Max=max(Max,querymax((i<<1)+1,mid+1,r,x,y));

returnMax;
}

intmain()
{

}
线段树模板终极版,区间求和,延迟标记
#include<iostream>
#include<cstdio>
usingnamespacestd;
constintmaxn=100000+10;
structnode{
intleft,right;
longlonglazy,sum;
voidupdate(longlongx){//延迟标记
sum+=(right-left+1)*x;
lazy+=x;
}
}tree[4*maxn];
inta[maxn];
inti;
voidpushdown(intid)
{
intl=tree[id].lazy;
if(l){
tree[id<<1].update(l);
tree[id<<1|1].update(l);
tree[id].lazy=0;
}
}

voidpushup(intid)
{
tree[id].sum=tree[id<<1].sum+tree[id<<1|1].sum;
}

voidbuild(intid,intl,intr)
{
tree[id].left=l;
tree[id].right=r;
tree[id].sum=tree[id].lazy=0;
if(l==r){
tree[id].sum=a[l];//这个地方一般是scanf!!!!!!!
return;
}

intmid=(l+r)>>1;
build(id<<1,l,mid);
build(id<<1|1,mid+1,r);
pushup(id);//更新
}

voidupdate(intid,intl,intr,intval)//区间更新
{
intL=tree[id].left,R=tree[id].right;
if(l<=L&&R<=r){
tree[id].update(val);
return;
}
else{
pushdown(id);
intmid=(L+R)>>1;
if(l<=mid)update(id<<1,l,r,val);
if(r>mid)update(id<<1|1,l,r,val);
pushup(id);
}
}

longlongquery(intid,intl,intr)//区间查询
{
intL=tree[id].left,R=tree[id].right;
if(l<=L&&R<=r)
returntree[id].sum;
else{
pushdown(id);
intmid=(L+R)>>1;
intres=0;
if(l<=mid)res+=query(id<<1,l,r);
if(r>mid)res+=query(id<<1|1,l,r);
pushup(id);
returnres;
}
}





                                            
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: