1. 程式人生 > >HDU-1698 Just a Hook 線段樹區間更新

HDU-1698 Just a Hook 線段樹區間更新

題意:一個長度為n的線段,q個操作,每個操作x,y,z是指把區間[x,y]內的值修改為z,最後求線段值的和。

思路:增加懶惰標誌,每次更新操作只更新到這個區間節點而不是這個區間的所有葉子結點。例如操作1,5,2。只更新到節點[1,5]而不是他的五個葉子結點。這個時候會把節點[1,5]節點標誌為2,如果接下來還有一個操作是1,3,3。那麼會先把節點[1,5]的兩個孩子[1,3],[4,5]置為2,然後更新操作[1,3],再重新把[1,5]置為-1,表示節點[1,5]並不能代表這個區間的所有值,因為他的兩個孩子的值都不一樣,pushdown函式就是用來實現這個功能的。另外更新的時候可以順便把節點和求出來,往上pushup一下,方便查詢。

#include <iostream>
#include <stdio.h>
#include <algorithm>
#include <cmath>
#include <string>
#include <cstring>
using namespace std;

typedef long long LL;
const int maxn = 1e5+10;
int sum[maxn << 2];
int lazy[maxn << 2];

void PushUp(int rt)
{
    sum[rt] = sum[rt << 1
] + sum[rt << 1 | 1]; } void pushdown(int rt,int len){ if(lazy[rt]!=-1){ lazy[rt<<1]=lazy[rt]; lazy[rt<<1|1]=lazy[rt]; sum[rt<<1]=lazy[rt]*(len-(len>>1)); sum[rt<<1|1]=lazy[rt]*(len>>1); lazy[rt]=-1; } } void
build(int l, int r, int rt) { sum[rt]=1; lazy[rt]=-1; if (l == r) { return; } int m = (l + r) >> 1; build(l, m, rt << 1); build(m + 1, r, rt << 1 | 1); PushUp(rt); } void update(int ll,int rr, int add, int l, int r, int rt) { if (ll<=l&&rr>=r) { lazy[rt]=add; sum[rt] = (r-l+1)*add; return; } pushdown(rt,r-l+1); int m = (l + r) >> 1; if(ll<=m) update(ll,rr, add, l, m, rt << 1); if(rr>m) update(ll,rr, add, m + 1, r, rt << 1 | 1); PushUp(rt); } int main() { int t,kase=1; scanf("%d",&t); while(t--){ int n; scanf("%d",&n); build(1,n,1); int q; scanf("%d",&q); for(int i=0;i<q;i++){ int x,y,z; scanf("%d%d%d",&x,&y,&z); update(x,y,z,1,n,1); } printf("Case %d: The total value of the hook is %d.\n",kase++,sum[1]); } return 0; }