标签:
这两周是数据结构专题的学习,,被专题的题目虐得死去活来==
线段树:简单的说就是把【1,n】的区间二分,【1,(1+n)/2】左子树,【(1+n)/2+1,n】右子树
就这样一直分下去,直到都是【x,x】这样的区间。这样就构成了一颗树了^-^
有这样一棵树,我们就可以在节点中储存区间的和啊,区间内的最大值啊,最小值等等。。这就是线段树的附加信息了,也是题目中的重点。。
我们可以用一个数组(长度为k)储存原区间的初始值,然后根据这个建树,所以这个树的节点数最多为4*K;
对于每个节点i,其左子树为i*2,右子树为i*2+1,父母节点为i/2。该区间的sum为左右子树区间和的和,最大最小值同理。。。
线段树的建立,修改,查询都是用递归写的。
所以在对单个数值时,必定会影响到其祖先节点,所以从上往下写。递归后修改节点信息。
线段树的查询也是如此,从上向下查询。
至于区间修改,,,我还在看。。。
对了,修改和查询的复杂度都是lgn
先贴模板
1 struct node 2 { 3 int maxt,sum; 4 int left,right; 5 }; 6 struct node tree[4*K]; 7 int a[k]; 8 void build(int id,int l,int r) 9 { 10 tree[id].left=l;tree[id].right=r; 11 if(l==r) 12 { 13 tree[id].maxt=tree[id].sum=a[l]; 14 } 15 else 16 { 17 build(2*id,l,(l+r)/2); 18 build(2*id+1,(l+r)/2+1,r); 19 tree[id].maxt=max(tree[2*id].maxt,tree[2*id+1].maxt); 20 tree[id].sum=tree[2*id].sum+tree[2*id+1].sum; 21 } 22 } 23 int queryMax(int id,int l,int r) 24 { 25 if(l==tree[id].left && r==tree[id].right) 26 return tree[id].maxt; 27 int mid=(tree[id].left+tree[id].right)>>1; 28 int ret=0; 29 if(r<=mid) 30 ret=max(ret,queryMax(id<<1,l,r)); 31 else if(l>=mid+1) 32 ret=max(ret,queryMax((id<<1)+1,l,r)); 33 else 34 { 35 int a,b; 36 a=queryMax(id<<1,l,mid); 37 b=queryMax((id<<1)+1,mid+1,r); 38 return max(a,b); 39 } 40 return ret; 41 } 42 int update(int id,int pos,int v) 43 { 44 if(tree[id].left == tree[id].right) 45 { 46 tree[id].sum=tree[id].maxt=val; 47 } 48 else 49 { 50 int mid=(tree[id].left+tree[id].right)>>1; 51 if (pos<=mid) update(id*2,pos,v); 52 else update(id*2+1,pos,v); 53 tree[id].sum=tree[id*2].sum+tree[id*2+1].sum; 54 tree[id].maxt=max(tree[id*2].maxt,tree[id*2+1].maxt); 55 } 56 return 0; 57 } 58 59 int query(int id,int l,int r) 60 { 61 if (tree[id].left==l&&tree[id].right==r) 62 return tree[id].sum; 63 else 64 { 65 int mid=(tree[id].left+tree[id].right)>>1; 66 if (r<=mid) return query(id*2,l,r); 67 else if (l>mid) return query(id*2+1,l,r) 68 else return query(id*2,l,mid)+query(id*2+1,mid+1,r); 69 } 70 }
标签:
原文地址:http://www.cnblogs.com/weeping/p/5423382.html