线段树

一直没写关于线段树的题解,简单的补两个部分。完整的请转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*/
区间最值
原文地址:https://www.cnblogs.com/upstart/p/8711872.html