【原创】tyvj1038 忠诚 & 计蒜客 管家的忠诚 & 线段树(单点更新,区间查询)
最简单的线段树之一,中文题目,不翻译。。。。
注释讲的比较少,这已经是最简单的线段树,如果看不懂真的说明最基础的理论没明白
推荐一篇文章http://www.cnblogs.com/liwenchi/p/5760498.html
可能和我的线段树风格不一样,无所谓啦,多理解,理解了就可以自己编自己喜欢风格的模板
前排强势提醒!!!线段树的函数中只要涉及到区间(更新/查询),就有一个很容易出错的点。
详情见我的另一篇:http://www.cnblogs.com/liwenchi/p/5761257.html
1 #include<iostream>
2 #include<cstdio>
3 #include<algorithm>
4 using namespace std;
5 #define N 1000003
6 int ans[1000003];
7 struct nod
8 {
9 int l,r;
10 int data;
11 }tree[5*N];
12
13 void push_up(int i)
14 {
15 tree[i].data = min(tree[i*2].data,tree[i*2+1].data);//更新tree[i]的最小值,由左孩子右孩子节点决定
16 }
17 void build_tree(int i,int l,int r)
18 {
19 tree[i].l=l;
20 tree[i].r=r;
21 tree[i].data = 0;
22 if(l==r)
23 {
24 return ;
25 }
26 int mid=(l+r)/2;
27 build_tree(i*2,l,mid);
28 build_tree(i*2+1,mid+1,r);
29 push_up(i); //理论上讲,建树不用加这个,加了也不错
30 }
31 void updata(int i,int k,int v)//更新
32 {
33 if(tree[i].l==k&&tree[i].r==k)
34 {
35 tree[i].data=v;
36 return ;
37 }
38 int mid=(tree[i].l+tree[i].r)/2;
39 if(k<=mid) //这里要是不懂,可以类比二叉排序树
40 updata(i*2,k,v);
41 else
42 updata(i*2+1,k,v);
43 push_up(i); //更新应该要加的啊哦,更新完以后,更新这个点的最小值
44 }
45
46 int query(int i,int l,int r)//查询
47 {
48 if(l<=tree[i].l&&tree[i].r<=r)
49 {
50 return tree[i].data;
51 }
52 int mid=(tree[i].l+tree[i].r)/2;
53 if(r<=mid) //如果R都小于MID了,说明一定是从左孩子节点来的(这里一开始怒错无数次,后来这样写过了,至今不知道为什么....)
54 return query(i*2,l,r);
55 if(l>mid) //如果L都大于MID了,说明一定是从右孩子节点来的
56 return query(i*2+1,l,r);
57 return min(query(i*2,l,r),query(i*2+1,l,r));//否则是从两个孩子节点来的,比较出最小值返回
58 }
59 int main()
60 {
61 int n,m,top = 0;
62 scanf("%d%d",&m,&n);
63 build_tree(1,1,m);
64 for(int i=1;i<=m;i++)
65 {
66 int account;
67 scanf("%d",&account);
68 updata(1,i,account);
69 }
70 for(int i=1;i<=n;i++)
71 {
72 int l,r;
73 scanf("%d%d",&l,&r);
74 ans[top++] = query(1,l,r);
75 }
76 for(int i=0;i<top-1;i++)
77 printf("%d ",ans[i]);
78 printf("%d",ans[top - 1]);//输出有点坑
79 }
当然也可以不要更新节点的函数,建树的时候直接把n组账单的值直接建到树里
我这种写法只是更具有一般性啦