Chapter 3. 数据结构 线段树
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Chapter 3. 数据结构 线段树相关的知识,希望对你有一定的参考价值。
Chapter 3. 数据结构 线段树
Sylvia‘s I.单点修改,区间查询.
模板:
//单点修改 区间求和
//1操作 单点修改
//2操作 区间求和 #include<cstdio> #include<iostream> using namespace std; #define MAXN 500005 int sum[MAXN<<2]; int n,m; void PushUp(int rt){//求和 sum[rt]=sum[rt<<1]+sum[rt<<1|1]; } void build(int l,int r,int rt){//建树 if (l==r){ scanf("%d",&sum[rt]); return; } int m=l+r>>1; build(l,m,rt<<1); build(m+1,r,rt<<1|1); PushUp(rt); } void Update(int P,int Add,int l,int r,int rt){//单点修改 if (l==r){ sum[rt]+=Add; return; } int m=l+r>>1; if (P<=m) Update(P,Add,l,m,rt<<1); else Update(P,Add,m+1,r,rt<<1|1); PushUp(rt); } int Query(int L,int R,int l,int r,int rt){//区间查询 if (L<=l&&r<=R) { return sum[rt]; } int m=l+r>>1; int ret=0; if (L<=m) ret+=Query(L,R,l,m,rt<<1); if (m<R) ret+=Query(L,R,m+1,r,rt<<1|1); return ret; } int step,x,k; int main (){ scanf("%d%d",&n,&m); build(1,n,1); for(int i=1;i<=m;i++){ scanf("%d%d%d",&step,&x,&k); if (step==1) Update(x,k,1,n,1); if (step==2) printf("%d\\n",Query(x,k,1,n,1)); } return 0; }
Sylvia‘s II. 区间修改,区间查询.
模板:参考自:bogo的线段树模板
//1操作 乘法操作 //2操作 加法操作 //3操作 询问区间和 //最后的结果对P取模 #include<cstdio> #include<iostream> #include<cmath> #include<algorithm> #include<cstring> using namespace std; #define MAX 100003 #define LL long long #define lson l,m,rt<<1 #define rson m+1,r,rt<<1|1 struct Segment_Tree{ LL sum[MAX<<2];//数组开四倍 LL lazy1[MAX<<2],lazy2[MAX<<2];//分别为乘法标记和加法标记 LL P;//取模 void PushUp(LL rt){//更新,对左右儿子求和 sum[rt]=sum[rt<<1]+sum[rt<<1|1]; sum[rt]%=P;//别忘记取模 } void build(LL l,LL r,LL rt){//建树 lazy1[rt]=1;//乘法标记记为1 lazy2[rt]=0;//加法标记记为0 if (l==r){ scanf("%lld",&sum[rt]); return; } LL m=l+r>>1; build(lson);//左子树 build(rson);//右子树 PushUp(rt);//及时更新 } void multiply (LL rt,LL x){//单乘 lazy2[rt]*=x;//(A[i]+lazy2[i])*lazy1[i]=A[i]*lazy1[i]+lazy2[i]*lazy1[i],所以加法标记要乘x lazy2[rt]%=P; lazy1[rt]*=x;//乘法标记当然也要乘…… lazy1[rt]%=P; sum[rt]*=x;//求和数组更要乘…… sum[rt]%=P; } void Add (LL rt,LL x,LL len){//单加 ,len为区间长度 lazy2[rt]=(lazy2[rt]+x)%P;//加法标记加 sum[rt]=(sum[rt]+(x*len)%P)%P;//求和数组加 } void PushDown (LL l,LL r,LL rt){ if (lazy1[rt]!=1){//如果有乘法标记 multiply(rt<<1,lazy1[rt]);//把标记下放到左儿子 multiply(rt<<1|1,lazy1[rt]);//把标记下放到右儿子 lazy1[rt]=1;//别忘记清除标记…… } if (lazy2[rt]){//如果有加法标记…… Add(rt<<1,lazy2[rt],(r+l>>1)-l+1); Add(rt<<1|1,lazy2[rt],r-(r+l>>1)); lazy2[rt]=0; } } void Addall(LL L,LL R,LL x,LL l,LL r,LL rt){//区间加 if (L<=l&&r<=R){//当前区间包含在需要查询的区间中 Add(rt,x,r-l+1); return; } LL m=l+r>>1; PushDown(l,r,rt); if (L<=m) Addall(L,R,x,lson);//如果需查询区间与左儿子有交集 if (m<R) Addall(L,R,x,rson);//如果需查询区间与右儿子有交集 PushUp(rt);//及时更新 } void Mullall(LL L,LL R,LL x,LL l,LL r,LL rt){// 区间乘 ,与上面类似…… if (L<=l&&r<=R){ multiply(rt,x); return; } LL m=l+r>>1; PushDown(l,r,rt);//不要忘记查询左右儿子之前先把标记下放,血的教训…… if (L<=m) Mullall(L,R,x,lson); if (m<R) Mullall(L,R,x,rson); PushUp(rt); } LL Query(LL L,LL R,LL l,LL r,LL rt){//区间查询 if (L<=l&&r<=R){ return sum[rt]; } LL ret=0; LL m=l+r>>1; PushDown(l,r,rt);// 不要忘记下放标记 if (L<=m) ret=(ret+Query(L,R,lson))%P; if (m<R) ret=(ret+Query(L,R,rson))%P; return ret; } }Seg; int main (){ LL n,m,step,x,y,z; scanf("%lld%lld%lld",&n,&m,&Seg.P); Seg.build(1,n,1);// for (int i=1;i<=m;i++){ scanf("%d",&step); switch(step){ case 1: scanf("%lld%lld%lld",&x,&y,&z); Seg.Mullall(x,y,z,1,n,1); break; case 2: scanf("%lld%lld%lld",&x,&y,&z); Seg.Addall(x,y,z,1,n,1); break; case 3: scanf("%lld%lld",&x,&y); printf("%lld\\n",Seg.Query(x,y,1,n,1)); break; } } return 0; }
活着
余华
老人和牛渐渐远去,我听到老人粗哑的令人感动的嗓音从远处传来,
他的歌声在空旷的傍晚像风一样飘扬,
老人唱道:
少年去游荡,中年想掘藏,老年做和尚。
炊烟在农舍的屋顶袅袅升起,在霞光四射的空中分散后消隐了。
女人吆喝孩子的声音此起彼伏,一个男人挑着粪桶从我跟前走过,扁担吱呀吱呀一路响了过去。
慢慢地,田野趋向了宁静,四周出现了模糊,霞光逐渐退去。
我知道黄昏正在转瞬即逝,黑夜从天而降了。
我看到广阔的土地袒露着结实的胸膛,
那是召唤的姿态,
就像,
女人召唤着她们的儿女,土地召唤着黑夜来临。
Sylvia
二零一七年五月十七日
以上是关于Chapter 3. 数据结构 线段树的主要内容,如果未能解决你的问题,请参考以下文章
数据结构 ---[实现 线段树(SegmentTree) ]