1. 程式人生 > >HDU1698 Just a Hook(線段樹區間更新、區間查詢)

HDU1698 Just a Hook(線段樹區間更新、區間查詢)

題目連結

題意

在 DotA 遊戲中,帕吉的肉鉤是很多英雄最害怕的東西。鉤子由連續若干段的等長金屬棒製成。

現在帕吉對鉤子由一些操作:

我們將金屬棒 1~n 依次編號,帕吉可以把編號 x~y 的金屬棒變成銅棒、銀棒、金棒。

每段銅棒的價值是 1;每段銀棒的價值是 2;每段金棒的價值是 3。

肉鉤的總價值是 n 段金屬棒價值之和。

帕吉想知道若干操作以後鉤子的總價值。

題解

線段樹區間更新、區間查詢問題。
區間更新原理:每一個節點代表一個區間上的資訊,對區間進行修改,即對若干個對應的節點進行修改。而考慮到暴力修改所有節點的時間複雜度難以接受,所以引入一個延遲標記。

也就是說只修改一個節點,而對該節點的子節點暫時不修改,等到下一次需要用到該節點的子節點時(包括更新和修改),再根據延遲標記進行修改。

程式碼

#include <cstdio>
#include <cstring>

using namespace std;

const int maxn=4e5+100;
int s[maxn],color[maxn];

void down(int p,int l,int r)
{
    if(color[p])
    {
        int mid=(l+r)/2;
        s[p*2]=(mid-l+1)*color[p];
        s[p*2+1]=(r-mid)*color[p];
        color[p*2]=color[p*2
+1]=color[p]; color[p]=0; } } void up(int p) { s[p]=s[p*2]+s[p*2+1]; } int query(int p,int l,int r,int x,int y) { if(x<=l && r<=y) { return s[p]; } down(p,l,r); int mid=(l+r)/2,ret=0; if(x<=mid) ret+=query(p*2,l,mid,x,y); if(y>mid) ret+=query(p*2
+1,mid+1,r,x,y); up(p); return ret; } void modify(int p,int l,int r,int x,int y,int z) { if(x<=l && r<=y) { s[p]=(r-l+1)*z; color[p]=z; return; } down(p,l,r); int mid=(l+r)/2; if(x<=mid) modify(p*2,l,mid,x,y,z); if(y>mid) modify(p*2+1,mid+1,r,x,y,z); up(p); } int main() { int T; scanf("%d",&T); for(int i=1;i<=T;i++) { memset(s,0,sizeof(s)); memset(color,0,sizeof(color)); int N; scanf("%d",&N); modify(1,1,N,1,N,1); int Q; scanf("%d",&Q); while(Q--) { int x,y,z; scanf("%d%d%d",&x,&y,&z); modify(1,1,N,x,y,z); } printf("Case %d: The total value of the hook is %d.\n",i,query(1,1,N,1,N)); } return 0; }