hdu 1698 Just a Hook (成段更新線段樹)
阿新 • • 發佈:2018-12-15
題目連結:哆啦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; }