【原创】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组账单的值直接建到树里
我这种写法只是更具有一般性啦