hdu 1698 Just a Hook (成段更新线段树)

版权声明:转载注明下出处就行了。 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;
}

猜你喜欢

转载自blog.csdn.net/LJD201724114126/article/details/84770614