线段树模板整理
struct node
{
int l,r;
ll sum;///(tag)
};
ll a[maxn];
node tr[maxn<<2];
至于为什么数组要开4倍(能用就行)
接下来就是如何建立这个线段树
void build(int x,int l,int r)
{
tr[x].l=l,tr[x].r=r;
if(l==r)
{
tr[x].sum=a[l];
return ;
}
int mid=l+r>>1;
build(x<<1,l,mid);
build(x<<1|1,mid+1,r);
tr[x].sum=tr[x<<1].sum+tr[x<<1|1].sum;
}
以及区间查询
ll query(int x,int l,int r)///interval sum
{
if(tr[x].l==l&&tr[x].r==r)
{
return tr[x].sum;
}
if(tr[x].tag!=0)///下推lazy_tag(区间更新时使用)
{
push_down(x);
}
int mid=tr[x].l+tr[x].r>>1;
if(l>mid) return query(x<<1|1,l,r);
else if(r<=mid) return query(x<<1,l,r);
else return query(x<<1,l,mid)+query(x<<1|1,mid+1,r);
}
单点维护
void update(int x/*查找x号元素*/ ,int y ,int node )///单点更新,将x号元素值更新为y
{
if(tr[node].l==x&&tr[node].r==x)
{
tr[node].sum=y;
return ;
}
int mid=tr[node].l+tr[node].y>>1;
if(x<=mid) update(x,y,node<<1);
else update(x,y,node<<1|1);
tree[node].sum=tr[node<<1].sum+tr[node<<1|1].sum;
}
区间维护
不同于单点维护,因为区间维护需要操作的是区间内所有节点,每次都更新的话效率较低,所以需要建立一个lazytag,用来先储存区间的操作,等到查询的时候再并到线段树里
即:如果某个区间内所有点都被增加了相同的值,则在lazytag中做上标记(以及add的值)
struct node
{
int l,r;
ll sum,tag;
};
ll a[maxn];
node tr[maxn<<2];
在后续访问到有lazytag的节点时,不用下推lazytag,如果要访问该节点的子节点,仅需要下推到两个子节点
void push_down(int x)
{
tr[x<<1].sum+=tr[x].tag*(tr[x<<1].r-tr[x<<1].l+1);
tr[x<<1|1].sum+=tr[x].tag*(tr[x<<1|1].r-tr[x<<1|1].l+1);
tr[x<<1].tag+=tr[x].tag;
tr[x<<1|1].tag+=tr[x].tag;
tr[x].tag=0;
}
以及区间更新函数
void itvupdate(int x,ll num,int l,int r)///interval update
{
if(l==tr[x].l&&r==tr[x].r)
{
tr[x].sum+=(r-l+1)*num;
tr[x].tag+=num;
return ;
}
if(tr[x].tag!=0)
push_down(x);
int mid=tr[x].l+tr[x].r>>1;
if(l>mid) itvupdate(x<<1|1,num,l,r);
else if(r<=mid) itvupdate(x<<1,num,l,r);
else
{
itvupdate(x<<1,num,l,mid);
itvupdate(x<<1|1,num,mid+1,r);
}
tr[x].sum=tr[x<<1].sum+tr[x<<1|1].sum;
}
end