【HDU - 1698】 Just a Hook(线段树模板 区间覆盖更新(laz标记) + 区间和查询 )
題干:
In the game of DotA, Pudge’s meat hook is actually the most horrible thing for most of the heroes. The hook is made up of several consecutive metallic sticks which are of the same length.?
Now Pudge wants to do some operations on the hook.?
Let us number the consecutive metallic sticks of the hook from 1 to N. For each operation, Pudge can change the consecutive metallic sticks, numbered from X to Y, into cupreous sticks, silver sticks or golden sticks.?
The total value of the hook is calculated as the sum of values of N metallic sticks. More precisely, the value for each kind of stick is calculated as follows:?
For each cupreous stick, the value is 1.?
For each silver stick, the value is 2.?
For each golden stick, the value is 3.?
Pudge wants to know the total value of the hook after performing the operations.?
You may consider the original hook is made up of cupreous sticks.?
Input
The input consists of several test cases. The first line of the input is the number of the cases. There are no more than 10 cases.?
For each case, the first line contains an integer N, 1<=N<=100,000, which is the number of the sticks of Pudge’s meat hook and the second line contains an integer Q, 0<=Q<=100,000, which is the number of the operations.?
Next Q lines, each line contains three integers X, Y, 1<=X<=Y<=N, Z, 1<=Z<=3, which defines an operation: change the sticks numbered from X to Y into the metal kind Z, where Z=1 represents the cupreous kind, Z=2 represents the silver kind and Z=3 represents the golden kind.?
Output
For each case, print a number in a line representing the total value of the hook after the operations. Use the format in the example.?
Sample Input
1 10 2 1 5 2 5 9 3Sample Output
Case 1: The total value of the hook is 24.題目大意:
在DOTA里有一個英雄 屠夫,他有一個肉鉤,巨長,然后默認都是黃銅做的,每一節(jié)的價值都為1。然后他要改變鉤子連續(xù)鏈節(jié),換成別的材質(zhì)。然后題目開始輸入樣例的個數(shù),然后是鉤子的鏈節(jié)數(shù),接下來是操作的次數(shù)。后面就是更改了,1是黃銅,2是白銀,3是金,價值也是這個數(shù)。
解題報告:
? ? ?區(qū)間覆蓋更新,區(qū)間和查詢。這個題目用到了線段樹對區(qū)間的更改,相對于單點改值,這個需要有一個pushdown函數(shù)。這個題目的話,我們現(xiàn)想一下更改區(qū)間的方法,最麻煩的方法就是從給出區(qū)間左端點一直遍歷修改到右端點,但是這樣的話相對來說時間復雜度有點高,難以接受,還有可能TLE。?
所以大佬們就想出來了,在節(jié)點當中加一個元素,那就是laz(lazy)元素,這個元素在建樹的時候都賦值為零,表示還沒有進行改值,然后改值更新的時候,直接在能夠被完全包含的區(qū)間上進行修改,因為是區(qū)間改值,并且修改的值都相同,所以就是修改值乘以區(qū)間長度給父節(jié)點作出相應處理就可以了,而不是一直改下去改到每一個葉節(jié)點,取而代之的是在該節(jié)點上記錄一下laz,代表這個區(qū)間內(nèi)的值有所改變,但是還沒有向分支傳遞。然后查詢的時候,如果需要這個區(qū)間內(nèi)子區(qū)間的值的話,那么就借助pushdown函數(shù)將laz下標傳遞給孩子節(jié)點。這樣說起來可能有點抽象,畫個圖,或者結(jié)合代碼思考一下就明白了。參考博客???????
AC代碼:
#include<bits/stdc++.h>using namespace std; const int MAXN = 100000 + 5; int n; int a[MAXN]; struct TREE {int l,r;int val;int laz; } tree[4*MAXN]; void pushup(int cur) {tree[cur].val = tree[2*cur].val + tree[2*cur + 1].val; } void build(int l ,int r,int cur) {if(l == r) {tree[cur].l = tree[cur].r = l;//寫成tree[r].r 了。。 tree[cur].val = a[l];tree[cur].laz = 0;return ;//這步return必須加!不然就無限遞歸了。這就是為什么寫遞歸函數(shù),要將出口寫在最前面,就是,不給他再次進入遞歸函數(shù)的機會! }int m = (l+r)/2;tree[cur].l = l;tree[cur].r = r; // tree[cur].val = 0;//加不加均可。 build(l,m,2*cur);build(m+1,r,2*cur + 1);pushup(cur); } void pushdown(int cur,int l,int r) {int m = (l+r)/2;if(tree[cur].laz !=0) {tree[2*cur].val = (m-l+1) *tree[cur].laz;tree[2*cur].laz = tree[cur].laz;tree[2*cur + 1].val = (r-m) * tree[cur].laz;tree[2*cur + 1].laz = tree[cur].laz;tree[cur].laz = 0;} } //pl-pr為查詢區(qū)間,l和r為樹種 當前cur下標 int query2(int pl,int pr,int l,int r,int cur) {if(pl<=l && pr>=r) return tree[cur].val; pushdown(cur,l,r);int m = (l+r)/2;int res = 0;if(pl <= m) res += query2(pl,pr,l,m,2*cur);//下面這里是if啊!!不是else!!! if(pr >= m+1) res += query2(pl,pr,m+1,r,2*cur + 1);return res; } void update2(int pl,int pr,int val,int l,int r,int cur) {if(pl<=l && pr >= r) {tree[cur].val = (r-l+1) * val;tree[cur].laz =val;return ;}pushdown(cur,l,r);int m = (l + r) / 2;if(pl <= m) update2(pl,pr,val,l,m,2*cur);if(pr >= m + 1) update2(pl,pr,val,m+1,r,2*cur+1);pushup(cur); } int main() {int t,m;int iCase = 0;int tmp1,tmp2;int op;cin>>t;while(t--) {printf("Case %d: ",++iCase);scanf("%d",&n);for(int i = 1; i<=n; i++ ) {a[i] = 1;}memset(tree,0,sizeof(tree));build(1,n,1); // for(int i = 1; i<=100; i++) printf("%d ",tree[i].val); // printf("\n");scanf("%d",&m);while(m--) {scanf("%d%d%d",&tmp1,&tmp2,&op);update2(tmp1,tmp2,op,1,n,1); // for(int i = 1; i<=100; i++) printf("%d ",tree[i].val); // printf("\n");}printf("The total value of the hook is %d.\n",query2(1,n,1,n,1)); // printf("%d %d ",tree[1].l,tree[1].r); // for(int i = 1; i<=100; i++) printf("%d ",tree[i].val); // printf("\n");} return 0 ;}?
總結(jié)
以上是生活随笔為你收集整理的【HDU - 1698】 Just a Hook(线段树模板 区间覆盖更新(laz标记) + 区间和查询 )的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: regsync.exe - regsyn
- 下一篇: ACM 题目分类POJ(自用,精)