版权声明:转载注明下出处就行了。 https://blog.csdn.net/LJD201724114126/article/details/84770614
题目链接:哆啦A梦传送门
题意:首先给出n个挂钩,每个挂钩的值都为1,接着Q次询问,每次 X,Y,Z,代表在区间 [X,Y]的挂钩都改为Z,
模板参考链接:https://www.cnblogs.com/TenosDoIt/p/3453089.html
题解:很显然这是用成段更新线段树去做,但我们需要变幻一下,延迟标记就不用+=,直接=。因为我们每次更新都只是改变值,不是加上,这样会不会产生多次更新而造成延迟标记会混乱呢?不会,因为每次更新时都是先把延迟标记先传下去,自己细想下就行。
贴个AC代码:
#include<cstring>
#include<cstdio>
#include<algorithm>
using namespace std;
const int maxn=100010;
struct node{
int val;
int addmark; ///延迟标记
}segtree[4*maxn];///定义线段树
/*
功能:构建线段树
root:当前线段树的根节点下标
arr: 用来构造线段树的数组
istart:数组的起始位置
iend:数组的结束位置
*/
void build(int root,int istart,int iend)
{
segtree[root].addmark=0; ///设置标延迟记域
if(istart==iend) ///叶子节点
segtree[root].val=1;
else{
int mid=(istart+iend)>>1;
build(root<<1,istart,mid); ///递归构造左子树
build(root<<1|1,mid+1,iend); ///递归构造右子树
///根据左右子树根节点的值,更新当前根节点的值
segtree[root].val=segtree[root<<1].val+segtree[root<<1|1].val;
}
}
/*
功能:当前节点的标志域向孩子节点传递
root: 当前线段树的根节点下标
*/
void pushdown(int root,int nstart,int nend)
{
if(segtree[root].addmark)
{
///设置左右孩子节点的标志域,这里我们直接用==,会不会出现叶子节点还没改变又覆盖了,
///我们完全不用这么疑问,因为每次更新时,一定是先传下去再更新的,自己细想下就行,所以是 “=”
int len=nend-nstart+1; ///左子树长度
int len1=((nend+nstart)>>1)-nstart+1; ///此区间总长度
segtree[root<<1].addmark=segtree[root].addmark;
segtree[root<<1|1].addmark=segtree[root].addmark;
segtree[root<<1].val=segtree[root].addmark*(len1);
segtree[root<<1|1].val=segtree[root].addmark*(len-len1);
///传递后,当前节点标记域清空
segtree[root].addmark=0;
}
}
/*
功能:线段树的区间查询
root:当前线段树的根节点下标
[nstart, nend]: 当前节点所表示的区间
[qstart, qend]: 此次查询的区间
*/
int query(int root,int nstart,int nend,int qstart,int qend)
{
///查询区间和当前节点区间没有交集
if(qstart>nend||qend<nstart)
return 0;
///当前节点区间包含在查询区间内
if(qstart<=nstart&&qend>=nend)
return segtree[root].val;
pushdown(root,nstart,nend); ///延迟标志域向下传递
int mid=(nstart+nend)>>1;
return query(root<<1,nstart,mid,qstart,qend)
+query(root<<1|1,mid+1,nend,qstart,qend);
}
/*
功能:更新线段树中某个区间内叶子节点的值
root:当前线段树的根节点下标
[nstart, nend]: 当前节点所表示的区间
[ustart, uend]: 待更新的区间
addVal: 更新的值(原来的值加上addVal)
*/
void updataone(int root,int nstart,int nend,int ustart,int uend,int addval)
{
///更新区间和当前节点区间没有交集
if(ustart>nend||uend<nstart)
return;
///当前节点区间包含在更新区间内
if(ustart<=nstart&&uend>=nend)
{
segtree[root].val=addval*(nend-nstart+1);
segtree[root].addmark=addval;
return;
}
///延迟标记向下传递
pushdown(root,nstart,nend);
int mid=(nstart+nend)>>1;
updataone(root<<1,nstart,mid,ustart,uend,addval);
updataone(root<<1|1,mid+1,nend,ustart,uend,addval);
///根据左右子树的值回溯更新当前节点的值
segtree[root].val=segtree[root<<1].val+segtree[root<<1|1].val;
}
int main()
{
int ncase;
scanf("%d",&ncase);
int n,m,T=0;
int x,y,z;
while(ncase--)
{
scanf("%d %d",&n,&m);
build(1,1,n);
for(int i=1;i<=m;i++){
scanf("%d%d%d",&x,&y,&z);
updataone(1,1,n,x,y,z);
}
printf("Case %d: The total value of the hook is %d.\n",++T,segtree[1].val);
}
return 0;
}