zoukankan      html  css  js  c++  java
  • 数据结构,线段树HDU1166

    #include<stdio.h>
    #include<stdlib.h>
    #include<string.h>
    typedef struct CNode
    {
    int L,R; //区间起点和终点
    int key;//兵力
    int add;//这是记录增量 
    struct CNode * left, * right;//放置左右孩子指针 
    }IT;
    IT *creat(int l,int r)//建树,用二叉链做,压力。。 
    {
       IT *s=(IT *)malloc(sizeof(IT));
       s->L=l;
       s->R=r;
       s->key=0;
       if(l==r)//左右相等,表示只有自己一个节点了 
       {
        s->left=s->right=NULL;
        s->key=0;
        return  s; 
       }
       else {
               s->left=creat(l,(r+l)/2);//没到底的话就继续往下开设节点 
               s->right=creat((r+l)/2+1,r);//
               s->key=s->left->key+s->right->key;//
               return  s;
            }
    }
    void change(IT *T,int l,int r,int x)
    {
         int mid;
         if(T->L==l&&T->R==r)//左右相等,表示找到了 
         {
            T->key+=x*(r-l+1);//找到后将所有下设的增量都加到总和里 
            T->add=x;//保留增量,不往下加,这里可以节省时间 
            return ;
         }
         if(T->add)
         {
           if(T->left)
            T->left->add+=T->add;
           if(T->right)
            T->right->add+=T->add;//这里要加上去并且清0是因为之前没有往下加,这次或查询或更新,都要改成正确的值 
            T->add=0;
         }
          mid=(T->L+T->R)/2;
         if(r<=mid)
         {
          change(T->left,l,r,x);//如果右边区间小于中部,说明在左侧,更新左子树 
         }
         else if(l>mid)
          change(T->right,l,r,x);//同上 
         else {
                 change(T->left,l,mid,x),change(T->right,mid+1,r,x);//同上 
              }
         T->key=T->left->key+T->right->key;//这里很重要,如果没这一句,叶子结点以上的根结点都没能得到更新 
    }
    int sum(IT *T,int l,int r)//求总和的算法跟更新的算法类似 
    {
        int mid=(T->L+T->R)/2;
        if(T->L==l&&T->R==r)//
         {
            return T->key;
         }
         if(T->add)
         {
           if(T->left)
            T->left+=T->add;
           if(T->right)
            T->right+=T->add;
            T->add=0;
         }
         if(r<=mid)
         return sum(T->left,l,r);//
         else if(l>mid)
         return sum(T->right,l,r);//
         else {
                 return (sum(T->left,l,mid)+sum(T->right,mid+1,r));//之所以要返回,是为了统计总和 
              }
    }
    int main()
    {
        int i,n,l,r,x,y,t,f=1;
        char s[20];
        IT *T;
        scanf("%d",&t);
        while(t--)
        {
           scanf("%d",&n);
           T=creat(1,n);
           for(i=1;i<=n;i++)
           {
              scanf("%d",&x);
              change(T,i,i,x);//边读入边更新,这里把更新当成插入了 
           }
           printf("Case %d:
    ",f++);
           while(scanf("%s",s),strcmp(s,"End"))
           {
               scanf("%d%d",&x,&y);
               if(strcmp(s,"Add")==0)
                 change(T,x,x,y);
               else if(strcmp(s,"Sub")==0)
                       change(T,x,x,-y);
               else printf("%d
    ",sum(T,x,y));
           }
        }
        return 0;
    }
    View Code

    http://acm.hdu.edu.cn/showproblem.php?pid=1166

    搞一下午的二叉链线段树,终于1A。。。。%>_<%

    线段树操作在三点

    一,建树:

    在网上找不到二叉链的代码,难道我奇葩了sro  orz

    结构体里保存有本身信息,增量,左右区间,孩子节点等等,在建树过程中,没用到一次函数,表示要启用一个节点,所以要重新申请,在判断函数给的左右

    区间是否相等后再进行操作,如果相等,表示找到要找的区间,赋值后返回,否则递归实现建树

    二,更新:

    在更新过程中,如果找到区间,就把增量,信息都赋予节点,否则将增量传与孩子节点的增量,记得相加,最后判断要找的区间往左往右,递归完成,

    其中要注意的事情是每过一个节点,都要把沿途的所有节点的信息进行修改,这里指总和

    三,查询:

    查询过程其实跟更新过程类似,只是要简单的返回和而已

  • 相关阅读:
    WPF学习10:基于MVVM Light 制作图形编辑工具(1)
    外文翻译 《How we decide》赛场上的四分卫
    算法学习01:二分查询,选择法、插入法、分治法排序
    外文翻译 《How we decide》 Introduction
    WPF学习09:数据绑定之 Binding to List Data
    WPF学习08:MVVM 预备知识之COMMAND
    WPF学习07:MVVM 预备知识之数据绑定
    WPF学习05:2D绘图 使用Transform进行控件变形
    WPF学习06:转换控件内容为可存储图片
    WPF学习04:2D绘图 使用Shape绘基本图形
  • 原文地址:https://www.cnblogs.com/huzhenbo113/p/3214495.html
Copyright © 2011-2022 走看看