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

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

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

    二,更新:

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

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

    三,查询:

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

  • 相关阅读:
    linux Linux下USB无线网卡WL167G、TLWN321G驱动安装过程详解
    linux CW_EPPC_8.8在linux下的安装和卸载
    linux Linux diff与patch的深入分析
    linux 嵌入式2.6.37wifivnt6656移植驱动
    linux 华为ET128 &中兴ZTE MU351移动TDSCDMA G3上网卡 .
    linux CW8.8 编译 提示缺少libstdc++.so.5的error
    linux codewarrior 8.8 for powerpc 在win7经常崩溃的解决方法
    linux ubuntu 安装smb共享文件夹
    [zt]c++builder调用VC的dll以及VC调用c++builder的dll
    电子认证服务管理办法
  • 原文地址:https://www.cnblogs.com/huzhenbo113/p/3214495.html
Copyright © 2011-2022 走看看