• 线段树(HDU1754)


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

    直接上代码和解释吧

     1 #include<iostream>
     2 #include<cstdio>
     3 #define maxn 200000
     4 int a[maxn],tree[maxn<<2];
     5 using namespace std;
     6 
     7 int max(int x,int y)
     8 {
     9     return x>y?x:y;
    10 }
    11 
    12 void pushup(int now)//更新下一层两支点最大值 
    13 {
    14     tree[now]=max(tree[now<<1],tree[now<<1|1]);
    15 }
    16 
    17 void build(int left,int right,int now)//构造数函数 
    18 {
    19     if(left==right)
    20     {
    21         tree[now]=a[left];
    22         return;
    23     }//赋值最底下一层数; 
    24     int mid=(left+right)>>1;
    25     build(left,mid,now<<1);
    26     build(mid+1,right,now<<1|1);
    27     pushup(now);//赋值最底下以上的数;
    28 }
    29 
    30 void update(int a,int b,int left,int right,int now)//更新节点信息 
    31 {
    32     if(right==a&&left==a)
    33     {
    34         tree[now]=b;
    35         return;
    36     }//跟新起始点值 ; 
    37     int mid=(left+right)>>1;
    38     if(a<=mid) update(a,b,left,mid,now<<1);
    39     else update(a,b,mid+1,right,now<<1|1);
    40     pushup(now);// 更新起始点以上有关的支点信息; 
    41 }
    42 
    43 int require(int L,int R,int left,int right,int now)//访问区间 ,L,R为给定的区间,另两个为正在访问的区间 
    44 {
    45     if(left>=L&&right<=R)
    46     {
    47         return tree[now];
    48     }//如果现在访问的区间在我们要找的区间里面,就返回这个区间的最大数节点 
    49     int mid=(left+right)>>1,ans=-1;
    50     if(L<=mid)
    51     ans=max(require(L,R,left,mid,now<<1),ans);//访问左半边 ; 
    52     if(mid<R)//两个if,两边都要考虑;
    53     ans=max(require(L,R,mid+1,right,now<<1|1),ans);//访问右半边,很巧。此处max里的ans为左半边的最大; 
    54     return ans;//所以直接返回ans值; 
    55 }

      接下来是对访问的解释(不记下来怕自己忘了):

    /*
    假设现有1 2 3 4 5 6 7 8 9 10 11 12数组
    现在要访问2-4
    第一步递归:因为1-12不在2-4里面,所以分为1-6和7-12两段,
    而因为6大于4;故7-12不会访问,若访问的为2-7则会,这也是右边判断里不用等号原因之一,我想用也行吧,但假如访问2-6时6就会被算两次;
    虽然最后不会影响判断最大值;
    第二次递归:中点为3,故1-6又被分为1-3,4-6;目前没有哪一段可以返回值;
    第三次递归: 分为4段:1-2;3-3;4-5;6-6;3-3(3-3在区间里)有返回值,并接下来的递归无6-6;
    第四次递归:(完全分段)1-1;2-2;4-4;5-5;(2-2;4-4)有返回值;
    结束递归,返回最大值;
    */

    继续代码:

     1 void mian(char str,int a,int b,int m)
     2 {
     3     if(str=='Q')
     4     {
     5         printf("%d
    ",require(a,b,1,m,1));
     6         return;
     7     }
     8     update(a,b,1,m,1);
     9 }
    10 
    11 int main()
    12 {
    13     int m,n;
    14     while(~scanf("%d %d",&m,&n))
    15     {
    16         char str;
    17         int x,y;
    18         for(int i=1;i<=m;i++)
    19         scanf("%d",&a[i]);
    20         build(1,m,1);
    21         getchar();
    22         while(n--)
    23         {
    24             scanf("%c%d%d",&str,&x,&y);
    25             mian(str,x,y,m);
    26             getchar();
    27         }
    28     }
    29     return 0;
    30 }

    另外一个很好的参考网站,写的很好,我得保存下来:https://blog.csdn.net/yitongjun/article/details/53193724

    总的来说:线段树是牺牲空间腾出时间的一个算法,里面有很多好巧的东西,让我边学边觉得不可思议,主要数的分支只有两个,造成每个节点与上一个节点有一定关系,即tree[n]的两个支点一定是tree[2*n]和tree[2*n+1];例外,关于线段树的操作函数有好几个,建树,访问树,修改树等,以后要多练习一下,里面递归作用梳理清楚后码起来还是可以的。嗯,这次就这样。

  • 相关阅读:
    webapp之路--meta标签format-detection、apple-mobile-web-app-capable
    js 进行年月日时间差计算
    JS手机邮箱身份证号码的正则验证以及通过身份证号码获取出生年月日
    react setState()方法可以只修改一个对象的部分属性
    js获取当前时间格式YYYY/MM/DD
    提高CSS开发能力的技巧集
    JavaScript专业规则12条
    为什么大型网站前端使用PHP后台逻辑用Java
    Cookie与Session的区别
    2016年JavaScript技术栈展望
  • 原文地址:https://www.cnblogs.com/wwq-19990526/p/8645418.html
Copyright © 2020-2023  润新知