所有的线段树各个部分的代码
//【单点查询】查询一个点的状态,设待查询点为x
void Ask(int k) //k表示结构体数组的编号
{
if(tree[k].l==tree[k].r) //当前结点的左右端点相等,是叶子节点,最终答案
{
ans=tree[k].w;
return ;
}
int mid=(tree[k].l+tree[k].r)/2;
if(x<=mid)
{
Ask(k*2); //目标位置比中点靠左,就递归左孩子else Ask(k*2+1); //反之,递归右孩子
}
}
//【单点修改】更改某一个点的状态。如:第x个数增加d
void Add(int k,int x,int d) //添加到点
{
if(x<Tree[k].a||x>Tree[k].b)
{
return;//不相交
}
if(Tree[k].a==Tree[k].b)
{
Tree[k].minn+=d;
return ;
}//边界叶结点Add(2*k,x,d); //递归左子树
Add(2*k+1,x,d); //递归右子树
Tree[k].minn=min(Tree[2*k].minn,Tree[2*k+1].minn);
}
//【区间询问】询问到区间
void Ask(int k,int L,int R) //询问到区间
{
if(R<Tree[k].a||L>Tree[k].b)
{
return; //不相交
}
if(L<=Tree[k].a&&R>=Tree[k].b)
{
minn=min(minn,Tree[k].min);
return;
}
Ask(2*k,L,R); //递归左子树
Ask(2*k+1,L,R); //递归右子树
}
//【区间修改】针对单点查询,不带懒标记
void Add(int v,int L,int R,int d)
{
if(L>tree[v].b||R<tree[v].a)
{
return; //不相交
}
if(L<=tree[v].a&&R>=tree[v].b)
{
tree[v].add+=d;
return;
}
Add(2*v,L,R,d); //递归左子树
Add(2*v+1,L,R,d); //递归右子树
}
//【单点查询】针对不带懒标记的区间修改
void Ask(int v,int x)
{
if(x>tree[v].b||x<tree[v].a)
{
return;
}
if(x>=tree[v].a&&x<=tree[v].b)
{
Ans+=tree[v].add;
}
if(tree[v].a==tree[v].b)
{
return; //边界叶结点Ask(2*v,x);
}
Ask(2*v+1,x);
}
//【懒标记的关键操作1】懒标记的下传
void Pushdown(int v) //标记下传
{
if(Tree[v].bj==-1) //已擦去,标记下传
{
Tree[v*2].bj=Tree[v*2+1].bj=-1;
Tree[v*2].s=Tree[v*2+1].s=0;
Tree[v].bj=0; //重要语句
}
if(Tree[v].bj==1) //已涂色,标记下传
{
Tree[v*2].bj=Tree[v*2+1].bj=1;
Tree[v*2].s=Tree[v*2].b-Tree[v*2].a+1;
Tree[v*2+1].s=Tree[v*2+1].b-Tree[v*2+1].a+1;
Tree[v].bj=0; //标记下传之后清空当前节点标记
}
}
//【插入操作】区间涂上颜色
void Pushup (int v)
{
Tree[v].s=Tree[v*2].s+Tree[v*2+1].s;
} //更新附加信息
void Insert(int v,int L,int R) //线段树的插入
{
if(Tree[v].b<L||Tree[v].a>R)
{
return; //若涂色的区域与该线段不相交,则退出
}
if(Tree[v].bj==1)
{
return;//若该线段被标记涂色,则退出//若涂色的区域覆盖了该线段,则该线段的状态变为被涂色,并退出
}
if(L<=Tree[v].a&&Tree[v].b<=R) //完全覆盖情况
{
Tree[v].bj=1;Tree[v].s=Tree[v].b-Tree[v].a+1;
return;
}
Pushdown(v); //标记下传
Insert(v*2,L,R); //插入左右子树
Insert(v*2+1,L,R);
Pushup (v); //重新计算本结点的附加信息
}
//【删除操作】区间擦去颜色
void Delete(int v,int L,int R) //线段树的删除
{
if(Tree[v].b<L||Tree[v].a>R)
{
return; //若删除的区域与该线段不相交,则退出
}
if(Tree[v].bj==-1)
{
return; //若该线段被标记删除,则退出
}
//若删除的区域覆盖了该线段,则该线段的状态变为未被涂色,并退出
if(L<=Tree[v].a&&Tree[v].b<=R)
{
Tree[v].bj=-1;Tree[v].s=0;
return;
}
Pushdown(v); //标记下传
Delete(v*2,L,R); //删除左右子树
Delete(v*2+1,L,R);
Pushup (v); //重新计算本结点的附加信息
}