hdu_1698 Just a Hook

来源:互联网 发布:mac获取最高权限 编辑:程序博客网 时间:2024/06/05 03:15

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

分析:

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

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

结构体如下:

#define MAXN 100010struct 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 100010struct 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~~,还是超时了。

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

原创粉丝点击