hdu_1698 Just a Hook

原题链接:http://acm.hdu.edu.cn/showproblem.php?pid=1698

分析:

     由样例输入输出可以看出来,这只胖子的肉钩的每个小段开始的时候是铜的。

      所谓的线段树整段更新问题,即区域覆盖问题。这个时候要把线段树的节点的值定义为颜色类型。。不再是区间的和了(不然就超时了)。

结构体如下:

#define MAXN 100010
struct Node
{
    int left,right;
    int num;  //标记颜色。1,2,3,-1(表在这个区间段是混合颜色);
}segTree[4*MAXN];

  还有就是延迟更新问题。因为是一个段更新的,找到该段后先不更新段下面的节点,到了以后要改变该段的值的时候再改变其子节点的值(最好拿样例自己模拟一遍)。

如   

       1 5 2; 找到[1,5]改变值,下面的子区间不改变。

       5 9 3;

      到[1,5]的时候,因为要改变[5,5]的值,所有[1,5]变成了混合颜色,赋值为-1;

      在赋值为-1之前,更新下面的节点[1,3],[4,5],这样子就可以减少不必要的更新了。




我的代码:

#include<stdio.h>
#define MAXN 100010
struct Node
{
    int l,r;
    int num;  //标记是否是同一种颜色。
}sT[4*MAXN];

void build(int i,int l,int r)
{
    sT[i].l=l;
    sT[i].r=r;
    if(l==r)
    {
        sT[i].num=1;
        return ;
    }
    int mid=(r+l)>>1;
    build(i<<1,l,mid);
    build(i<<1|1,mid+1,r);
    sT[i].num=1; //开始的时候都是颜色1.
}
void modfiy(int i,int a,int b,int m)//把[a,b]区间的位置改成颜色m
{
    //要明白在[a,b]是sT[i].l,sT[i].r的子集。
    //所以当[a,b]的值等于sT[i].l,sT[i].r区间的值的时候,就直接返回;
    if(sT[i].num==m) return; //改的值和原来的一样,就不用改。
   if(a==sT[i].l&&sT[i].r==b)
   {
       sT[i].num=m;
       return;
   }
   /**接下来,要改变[sT[i].l,sT[i].r]的值了
    **如果此区间不是混合区间,就把他得值给左右孩子。
    **这就是所谓的延迟更新,到了不得不更新的时候再跟新。
    **/
   if( sT[i].num!=-1)
   {
       sT[i<<1].num=sT[i<<1|1].num=sT[i].num;
   }
   sT[i].num=-1; //-1表混合区间
   int mid=(sT[i].r+sT[i].l)>>1;
   if(b<=mid)
   {
       modfiy( i<<1, a, b, m);
   }
   else if(a>mid)
   {
       modfiy( i<<1|1, a, b, m);
   }
   else
   {
       modfiy( i<<1, a, mid, m);
       modfiy( i<<1|1, mid+1, b, m);
   }
}
int sumTree(int i,int a,int b)
{
    //[a,b]是当前节点的子区间。
    //如果这个大区间是一个值,则可以之间返回。
    if(sT[i].num>0) //不是杂区间。
    {
        return sT[i].num*(b-a+1);
    }
    int mid=(sT[i].r+sT[i].l)>>1;
    if(b<=mid) sumTree(i<<1,a,b);
    else if(a>mid) sumTree(i<<1|1,a,b);
    else return sumTree(i<<1,a,mid)+sumTree(i<<1|1,mid+1,b);
}
int main()
{
    int t,k;
    scanf("%d",&t);
    for(k=1;k<=t;k++)
    {
        int n,m;  //[1,n];
        scanf("%d%d",&n,&m);
        build(1,1,n);
        for(int j=0;j<m;j++)
        {
            int a,b,v;
            scanf("%d%d%d",&a,&b,&v);
            modfiy(1,a,b,v);
        }
        printf("Case %d: The total value of the hook is %d.\n",k,sumTree(1,1,n));
    }
    return 0;
}

总结:

        一开始用线段树的节点的表示区间的总和,果断超时。这道题对线段树的维护与hdu_1166(敌兵布阵)是不一样的。本题是整段改变值,后者是点改变;本题是做一连串改变后输出总值,后者是改一改输出一下值。

        也试过有hdu_1166的结构,每次改变叶子节点的值的时候,不往上更新,等所有叶子节点的都改变后,再从root节点往下更新区间的总和。一开始以为自己的思想有多棒o(≧v≦)o~~,还是超时了。

       有事一种新线段树权值结构,还有的学。(*^__^*) 。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值