skkyk:线段树浅谈

推荐前辈学姐博客文章,写的很细html

http://www.javashuo.com/article/p-ddxbfjfo-dk.htmlnode

学学半,此随笔主要是加深本身对线段树的理解数组

题目:洛谷P3374模(mu)板题ui

(话说为何是树状数组,主要是由于我太菜了不会懒标记)spa

//代码中的位运算其实就是乘除2的一些操做
#include<cstdio> using namespace std; int n,m,ans; struct node { int left,right,num; }tree[500000*4+5];//经典的四倍空间,我也不知道为何 int input[500000+5]; void build(int index,int l,int r)//建树,一棵满二叉树 { tree[index].left=l,tree[index].right=r; if(l==r) { tree[index].num=input[l]; return ; } int mid=(l+r)>>1; build(index<<1,l,mid);build(index<<1|1,mid+1,r); tree[index].num=tree[index<<1].num+tree[index<<1|1].num; } void add(int index,int target,int k)//单点修改,变量是序号、目标、修改值 { tree[index].num+=k;//对于每一个能够递归到的点都是包含目标target这个点的集合,都要一并加上k if(tree[index].left==tree[index].right)//单点集合返回 return ; if(target<=tree[index<<1].right) add(index<<1,target,k); if(target>=tree[index<<1|1].left) add(index<<1|1,target,k);//两个if语句都是判断是否存在交集,是则进行下一层 } void query(int index,int l,int r)//区间求和(区间查询) { if(tree[index].right<=r&&tree[index].left>=l) { ans+=tree[index].num;//对于区间的子集累计答案 return ;//避免累计区间子集的区间子集 ??exm } if(tree[index].right==tree[index].left) return ; if(tree[index<<1].right>=l) query(index<<1,l,r); if(tree[index<<1|1].left<=r) query(index<<1|1,l,r);//同为寻找交集 return ; } int main() { scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) scanf("%d",input+i); build(1,1,n);//建树 for(int i=1,a,x,y;i<=m;i++) { scanf("%d%d%d",&a,&x,&y); if(a==1) add(1,x,y);//单点修改 if(a==2) { ans=0; query(1,x,y);//区间查询 printf("%d\n",ans); } }
  return 0; }

等改天问一下学长们懒标记的具体code

相关文章
相关标签/搜索