1. 程式人生 > >hdu 1698 Just a Hook (成段更新線段樹)

hdu 1698 Just a Hook (成段更新線段樹)

題目連結:哆啦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;
}