• 线段树


    一直没写关于线段树的题解,简单的补两个部分。完整的请转https://blog.csdn.net/yrhsilence/article/details/5793699

    线段树做了很多,感觉这类题其实比别的算法更简单,只不过代码量比较大。

    关于树,大家明白一点就行

                                    父节点 n

                                         ——                ——

                                  父节点*2                      父节点*2+1

    即                           n*2                              n*2+1

    二进制中                左移1位                        左移1位+1

    下面,我简单说两类,一个是区间求和,一个是区间求最值

    1.hdu1166 敌兵布阵  

     1 #include <stdio.h>
     2 #include <math.h>
     3 #include <stdlib.h>
     4 #include <string.h>
     5 #include <string>
     6 #include <algorithm>
     7 #include <iostream>
     8 #include <ctype.h>
     9 #include <set>
    10 #include <map>
    11 #include <vector>
    12 #include <stack>
    13 #include <queue>
    14 #define left (now<<1)
    15 #define right ((now<<1)+1)
    16 #define mid ((l+r)>>1)
    17 #define fst first
    18 #define snd second
    19 using namespace std;
    20 typedef long long lint;
    21 
    22 struct segmentTree{
    23     int sum;
    24 };
    25 
    26 int t,n,a[50010];
    27 char str[10];
    28 segmentTree tree[2000010];
    29 
    30 void buildTree(int now,int l,int r){   //建树
    31     if(l == r){
    32         tree[now].sum = a[l]; return;
    33     }
    34     buildTree(left,l,mid); buildTree(right,mid+1,r);
    35     tree[now].sum = tree[left].sum + tree[right].sum;
    36     return;
    37 }
    38 
    39 void updateTree(int now,int l,int r,int set,int setNum){  //更新树
    40     if(l == r){
    41         tree[now].sum += setNum;
    42         return;
    43     }
    44     if(set <= mid){
    45         updateTree(left,l,mid,set,setNum);
    46     }else{
    47         updateTree(right,mid+1,r,set,setNum);
    48     }
    49     tree[now].sum = tree[left].sum + tree[right].sum;
    50 }
    51 
    52 int getSum(int now,int l,int r,int ql,int qr){   //求和
    53    if(ql == l && qr == r){
    54        return tree[now].sum;
    55    } 
    56    int re = 0;
    57    if(ql <= mid){
    58        re += getSum(left,l,mid,ql,min(qr,mid));
    59    }
    60    
    61    if(qr > mid){
    62        re += getSum(right,mid+1,r,max(ql,mid+1),qr);
    63    }
    64    return re;
    65 }
    66 
    67 int main(){
    68     scanf("%d",&t);
    69     int ca = 0;
    70     while(t--){
    71         ++ca;
    72         memset(a,0,sizeof(a));
    73         scanf("%d",&n);
    74         for(int i = 1; i <= n; ++i){
    75             scanf("%d",&a[i]);
    76         }
    77         scanf("%s",str);
    78         buildTree(1,1,n);
    79         printf("Case %d:n",ca);
    80         while(str[0] != 'E'){
    81             if(str[0] == 'A'){
    82                 int u,v;
    83                 scanf("%d%d",&u,&v);
    84                 updateTree(1,1,n,u,v);
    85             }else if(str[0] == 'S'){
    86                 int u,v;
    87                 scanf("%d%d",&u,&v);
    88                 updateTree(1,1,n,u,-v);
    89             }else if(str[0] == 'Q'){
    90                 int u,v;
    91                 scanf("%d%d",&u,&v);
    92                 int ans = getSum(1,1,n,u,v);
    93                 printf("%dn",ans);
    94             }
    95             scanf("%s",str);
    96         }
    97     }
    98 }
    区间求和

    (其实有一种后缀数组做这个题更好,这里主要是为了练一下线段树,树状数组可以放一放)

     1 #include"stdio.h"
     2 #include"string.h"
     3 long long lqq[50005];
     4 int n;
     5 int lowbit(int x)
     6 {
     7     return x&(-x);
     8 }
     9 void insert(int i,int k)
    10 {
    11     while(i<=n)
    12     {
    13         lqq[i]+=k;
    14         i+=lowbit(i);
    15     }
    16 }
    17 long long getsum(int n)
    18 {
    19     long long sum=0;
    20     while(n)
    21     {
    22         sum+=lqq[n];
    23         n-=lowbit(n);
    24     }
    25     return sum;
    26 } 
    27 int main()
    28 {
    29     int t,i,k,T=1;
    30     char s[10];
    31     scanf("%d",&t);
    32     while(t--)
    33     {
    34         printf("Case %d:
    ",T++);
    35         memset(lqq,0,sizeof(lqq));
    36         scanf("%d",&n);
    37         for(i=1;i<=n;i++)
    38         {
    39             scanf("%d",&k);
    40             insert(i,k);
    41         }
    42         scanf("%s",s);
    43         while(strcmp(s,"End"))
    44         {
    45             scanf("%d%d",&i,&k);
    46             if(strcmp(s,"Add")==0)
    47             insert(i,k);
    48             else if(strcmp(s,"Sub")==0)
    49             insert(i,-k);
    50             else printf("%d
    ",getsum(k)-getsum(i-1));
    51             scanf("%s",s);
    52         }
    53     }
    54     return 0;
    55 }
    树状数组

    2.hdu1754 I Hate It

    这个题真的很有意思,而且跟2017年acm区域赛网络资格赛的一个题超级像!!!务必好好看一下

      1 #include<iostream>
      2 #include<cmath>
      3 #include<cstdio>
      4 
      5 //hduoj 1754  G++
      6 
      7 
      8 const int  MAXN = 800000;
      9 using namespace std;
     10 
     11 struct node
     12 {
     13     int left,right,value;
     14 } node[MAXN];
     15 int father[MAXN];
     16 
     17 int MAX(int x,int y)
     18 {
     19     return x>=y ? x:y;
     20 }
     21 
     22 //建树
     23 void Build(int i, int left,int right)
     24 {
     25     node[i].left = left ;
     26     node[i].right = right ;
     27     node[i].value = 0;
     28     if(left == right)
     29     {
     30         father[left] = i;
     31         return ;
     32     }
     33     Build((i << 1) , left, (int)( floor(left + right) / 2.0 ));
     34     Build((i << 1)+1 , (int)( floor(left + right)/2.0)+1 , right );
     35 }
     36 
     37 
     38 //更新
     39 void Update(int ri)
     40 {
     41     if( ri == 1)
     42         return ;
     43     int fi = ri / 2 ;
     44     int a,b;
     45     a = node[fi<<1].value;
     46     b = node[ (fi<<1) +1].value;
     47     node[fi].value = MAX(a,b);
     48     Update(ri / 2) ;
     49 }
     50 
     51 
     52 //查询
     53 int Max;
     54 void Query(int i, int l, int r)
     55 {
     56     if(node[i].left == l && node[i].right == r )
     57     {
     58         Max = MAX(Max, node[i].value );
     59         return ;
     60     }
     61     i = i << 1 ;
     62     if( l <= node[i].right )
     63     {
     64         if(r <= node[i].right)
     65             Query(i, l, r );
     66         else
     67             Query(i, l, node[i].right );
     68     }
     69     i++;
     70     if( r>= node[i].left )
     71     {
     72         if( l >= node[i]. left )
     73             Query(i, l, r );
     74         else
     75             Query( i, node[i].left, r);
     76     }
     77 }
     78 
     79 
     80 //主函数
     81 int main()
     82 {
     83     int n,m,g;
     84     while(scanf("%d%d", &n,&m )!=EOF)
     85     {
     86         Build( 1, 1, n );
     87         for(int i = 1 ; i <= n ; i++ )
     88         {
     89             scanf("%d", &g );
     90             node[father[i]].value = g;
     91             Update(father[i]);
     92         }
     93         string op;
     94         int a,b;
     95         while(m--)
     96         {
     97             cin>>op>>a>>b;
     98             if(op[0] == 'Q')
     99             {
    100                 Max = 0;
    101                 Query(1,a,b);
    102                 cout<<Max<<endl;
    103             }
    104             else
    105             {
    106                 node[father[a]].value  = b;
    107                 Update(father[a]);
    108             }
    109         }
    110     }
    111 }
    112 /*5 6
    113 1 2 3 4 5
    114 Q 1 5
    115 U 3 6
    116 Q 3 4
    117 Q 4 5
    118 U 2 9
    119 Q 1 5
    120 
    121 5  6  5  9*/
    区间最值
  • 相关阅读:
    Hibernate:组合模式解决树的映射
    以面到点的学习MFC
    linux内核--进程与线程
    控件自定义
    火车车次查询-余票查询--Api接口
    如何处理大量数据并发操作(数据库锁机制详解)
    Java单链表、双端链表、有序链表实现
    事务、数据库事务、事务隔离级别、锁的简单总结
    数据库连接池分析
    Spring面试题集
  • 原文地址:https://www.cnblogs.com/upstart/p/8711872.html
Copyright © 2020-2023  润新知