skkyk:线段树浅谈
程序员文章站
2022-10-08 18:26:48
推荐前辈学姐博客文章,写的很细 https://www.cnblogs.com/TheRoadToTheGold/p/6254255.html 学学半,此随笔主要是加深自己对线段树的理解 题目:洛谷P3374模(mu)板题 (话说为什么是树状数组,主要是因为我太菜了不会懒标记) 等改天问一下学长们懒 ......
推荐前辈学姐博客文章,写的很细
https://www.cnblogs.com/theroadtothegold/p/6254255.html
学学半,此随笔主要是加深自己对线段树的理解
(话说为什么是树状数组,主要是因为我太菜了不会懒标记)
//代码中的位运算其实就是乘除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; }
等改天问一下学长们懒标记的具体