zoukankan      html  css  js  c++  java
  • 线段树

    线段树札记

     

    线段树不是区间树,线段树是一种二叉搜索树,与区间树相似,它将一个区间划分成一些单元区间,每个单元区间对应线段树中的一个叶结点。注意他是把一段连续的区间分为单元区间为叶子节点的一颗数,以此为基础,展开一系列牛逼的计算。

    首先就是如何建立这么一个线段树?

    如此递归地建立,对于线段树中的每一个非叶子节点[a,b],它的左儿子表示的区间为[a,(a+b)/2],右儿子表示的区间为[(a+b)/2+1,b]。就可以建立一张如下图的线段树:

     

      伪代码:

      construct(index,left,right) {
    
     tree[index].left = left;
    
     tree[index].right = right;
    
     if left=right
    
       return;
    
     mid = (left+right)/2
    
    construct(2*index,left,mid)
    
    construct(2*index+1,mid+1,right)
    
    }
    

       如此一个线段树就创建好了,父亲节点与孩子节点是index->(2*index,2*index+1),用此来创建一颗二叉树,所以在结构体里面只需要两个字段一个是left,一个是right

      创建好线段树之后,一个重要操作就是插入操作,这个是奠定后面各种牛逼操作的基础。那么如何插入一段区间呢?(假设区间为[begin,end])

     insert(index,begin,end)
    
    if begin=tree[index].left&&end=tree[index].right=end  //注意这里是等于号
    
      tree[index].cover++
    
    int mid = (tree[index].left+tree[index].right)/2
    
    if mid >=end
    
      insert(2*index,begin,end)
    
    else
    
      insert(2*index+1,begin,end)
    
    end
    
    end

    这里为cover添加了一个字段cover,计算这段区间的区间

    这个cover是后面用来查询用的

     

    到目前为止,该用的数据结构已经维护好了。现在开始用了,查询一个点在区间中出现的次数。 从根节点开始到[x,x]叶子的这条路径中所有点计数相加方为x出现次数 

     查询x在区间中出现的次数。

    query(index,x)
    
     mid = (tree[index].left + tree[index].right)/2
    
     if x<=mid
    
      return query(2*index,x)+tree[index].cover
    
    else
    
      return query(2*index+1,x)+tree[index].cover
    
    end
    

    题目练习 

    1,单点更新

     HDU 敌兵布阵

     题目很简单就是一道赤裸裸的线段树的题目。不过好久没敲代码了,生疏了,还是被一些小问题搞得很烦,可能自己内心也是太烦了。

     最坑爹的是strcmp(str,"End")和str=="End"字符串的比较吧

     占位符。。。。。。。。。。。。。

     对于一个单节点更新的时候可以从上往下寻找的时候就更新节点的cover域,也可以在回朔的时候更新节点的cover域;

        if(x>=tree[index].left&&x<=tree[index].right) // >=  -> == 
         {
             tree[index].cover += value;
             if(tree[index].left==x&&tree[index].right==x)
                 return;
         }
    

     也可以在

      int mid=(tree[index].left+tree[index].right)/2;
         if(mid>=x) //sometime i forget to consider the equal condition,but it's important; 
            update(2*index,x,value);
         else
            update(2*index+1,x,value); 
         //tree[index].cover += value; 对于单节点更新,是在查找的时候更新父亲节点,还是回朔时候更新父亲节点都是可行的 
    

    代码:

    #include<stdio.h>
    #include<string.h>
    
    #define MAX 50010
    
    struct Node
    {
           int left;
           int right;
           int cover;
    };
    Node * tree= new Node[MAX*4];
    
    int data[MAX];
    
    void build(int index,int left,int right)
    {
         tree[index].left = left;
         tree[index].right= right;
         //printf("%d %d %d
    ",index,left,right);
         if(left==right)
         {
            tree[index].cover = data[left];
            // printf("%d %d %d %d
    ",index,left,right,tree[index].cover);
            return;
         }
         int mid = (left+right)/2;
         build(2*index,left,mid);
         build(2*index+1,mid+1,right);
         tree[index].cover = tree[2*index].cover + tree[2*index+1].cover; //update parent's cover field,not just update leaf node   
    }
    
    void update(int index,int x,int value)
    {
         
         //printf("%d %d %d
    ",index,tree[index].left,tree[index].right);
         if(x>=tree[index].left&&x<=tree[index].right) // >=  -> == 
         {
             tree[index].cover += value;
             if(tree[index].left==x&&tree[index].right==x)
                 return;
         }
    
         int mid=(tree[index].left+tree[index].right)/2;
         if(mid>=x) //sometime i forget to consider the equal condition,but it's important; 
            update(2*index,x,value);
         else
            update(2*index+1,x,value); 
         //tree[index].cover += value; 对于单节点更新,是在查找的时候更新父亲节点,还是回朔时候更新父亲节点都是可行的 
    }
    
    int query(int index,int left,int right)
    {
        //printf("%d %d %d
    ",index,left,right);
        //getchar();
        if(left==tree[index].left&&right==tree[index].right)
        {
           return tree[index].cover;
        }
        int mid=(tree[index].left+tree[index].right)/2;
        if(mid>=right)
           return query(2*index,left,right);
        else if(mid<left)
           return query(2*index+1,left,right);
        else
           return query(2*index,left,mid)+query(2*index+1,mid+1,right);
    }
    
    int main()
    {
        int T,N;
        char  str[20];
        scanf("%d",&T);
        int p,v;
        for(int s = 1; s <= T;s++)
        {
           //printf("%d",MAX*4);
           memset(tree,0,sizeof(Node)*MAX*4);
           memset(data,0,sizeof(int)*MAX);
           scanf("%d",&N);
           for(int i = 1; i<=N;i++)
           {
            scanf("%d",&data[i]);
           }
           build(1,1,N);
         //  for(int i = 1;i<=4*N;i++)
        //   {
        //      printf("%d ",tree[i].cover);
       //    }
           printf("Case %d:
    ",s);
           while(true) //while(scanf("%s",str)&&str!="End") str为End时候不起作用 
           {
               scanf("%s",str);
              // printf("%s",str);
               if(strcmp(str,"End")==0)
                  break;
               scanf("%d%d",&p,&v);
               if(strcmp(str,"Add")==0)
               {
                 update(1,p,v);                       
               }else if(strcmp(str,"Sub")==0){
                 update(1,p,-v);
               }
               else if(strcmp(str,"Query")==0)
               {
                 printf("%d
    ",query(1,p,v));
               }
           }  
          // printf("end %d",s);
        }
        return 0;
    } 
    

    推荐文章:

        http://blog.csdn.net/wypblog/article/details/8219727

       http://www.cnblogs.com/superbin/archive/2010/08/02/1790467.html

       动态统计,线段树的问题。

       可以更新某一个值,查询某一段区间的和

       也可以更新一段区间,查询某一个元素的值

       这四种操作都是线段树必须考虑的问题。

       

     
  • 相关阅读:
    jQuery命名空间,自定义空间及属性,插件开发全解析 (转)
    打印输入表单中的内容
    js 网页烟花效果
    js学习cookie封装之获取
    js学习cookie封装之添加
    git基本使用
    最简单的手风琴效果
    js学习cookie封装之删除
    21个值得收藏的javas技巧
    javascript常用特效汇总
  • 原文地址:https://www.cnblogs.com/championlai/p/3721829.html
Copyright © 2011-2022 走看看