数据结构,线段树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:\n",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\n",sum(T,x,y));
       }
    }
    return 0;
}
View Code

 

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

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

线段树操作在三点

一,建树:

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

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

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

二,更新:

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

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

三,查询:

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

转载于:https://www.cnblogs.com/huzhenbo113/p/3214495.html

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值