[線段樹 段更新] HDU - 1698 E - Just a Hook

            **[線段樹 段更新] HDU - 1698 E - Just a Hook**

題目大意:有一個長度爲n的鉤子,它由n個小鉤子構成,每個小鉤子初值爲1。由一種操作,對於區間
[x,y],將該區間內每個小鉤子的值更新爲x(1<=x<=3)。求最後大鉤子的總價值。
分析:剛開始做線段樹,第一次寫的時候我只是單純更新相應區間,沒有考慮當區間不是正好包含的時候,一直不對。第二次,我每次更新都更新到葉子,果斷T。。。然後我就用了最入門的段更新的方法(一開始我想了想感覺沒必要),看到別的博客說叫做懶惰標記。。。

#include <stdio.h>
struct node
{
    int l,r;
    int sum;
    int lnc;//增量 
};
node tree[400005];
int mid(int root)
{
    return (tree[root].l+tree[root].r)/2;
}
void BuildTree(int root,int l,int r)//建樹 初始化 
{
  tree[root].l=l;
  tree[root].r=r;
  tree[root].sum=r-l+1;
  tree[root].lnc=0;
  if(l!=r)
  {
    BuildTree(2*root+1,l,mid(root));
    BuildTree(2*root+2,mid(root)+1,r);
  } 
}
void updata(int root,int a,int b,int v)
{
    if(tree[root].l==a&&tree[root].r==b)//當前區間與操作區間完全重合,直接更新sum,打上標記 
    {
        tree[root].sum=(b-a+1)*v;
        tree[root].lnc=v;
        return;
    }
    if(tree[root].lnc!=0)//不完全重合時,如果存在標記,左右更新標記 
    {
     updata(2*root+1,tree[root].l,mid(root),tree[root].lnc);
     updata(2*root+2,mid(root)+1,tree[root].r,tree[root].lnc);  
     tree[root].lnc=0;//消除標記 
    }
    //判斷區間情況 遞歸更新 
    if(b<=mid(root))
    {
      updata(2*root+1,a,b,v);
    }
    else if(a>mid(root))
    {
      updata(2*root+2,a,b,v);   
    }
    else
    {
      updata(2*root+1,a,mid(root),v);
      updata(2*root+2,mid(root)+1,b,v); 
    }
    //函數回溯時,直接更新當前節點的sum 
    tree[root].sum=tree[2*root+1].sum+tree[2*root+2].sum;   
}
int main(int argc, char *argv[])
{
    int T;
    scanf("%d",&T);
    int ans=0;
    while(T--)
    {
        int n;
        scanf("%d",&n);
        BuildTree(0,1,n);
        int q;
        scanf("%d",&q);
        int x,y,z;
        for(int i=0;i<q;i++)
        {
          scanf("%d %d %d",&x,&y,&z);
          updata(0,x,y,z);
        }
        printf("Case %d: The total value of the hook is %d.\n",++ans,tree[0].sum);
    }
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章