POJ 3468 A Simple Problem with Integers(区间更新)
来源:互联网 发布:不动点 知乎 编辑:程序博客网 时间:2024/05/16 18:13
A Simple Problem with Integers
Time Limit:5000MS Memory Limit:131072KB 64bit IO Format:%lld & %lluDescription
给出了一个序列,你需要处理如下两种询问。
"C a b c"表示给[a, b]区间中的值全部增加c (-10000 ≤ c ≤ 10000)。
"Q a b" 询问[a, b]区间中所有值的和。
Input
第一行包含两个整数N, Q。1 ≤ N,Q ≤ 100000.
第二行包含n个整数,表示初始的序列A (-1000000000 ≤ Ai ≤ 1000000000)。
接下来Q行询问,格式如题目描述。
线段是区间更新的裸题,来吧,学区间更新,前面我们学了线段树的点更新,比较好理解而且很好实现,但是当对一个区间进行操作的时候就不行,要对区间的每一个数进行修改会TLE,所以要学线段树的区间更新,首先现在结构体里面加上一个变量add,这是一个标记,标记的是当前节点所负责的区间进行的操作,我们只需要标记这个add并不需要传递。
首先来看建树,在建树时和普通的线段树一样,但是要对每一个节点的add标记置0。
void build(int id,int l,int r){ tree[id].l=l; tree[id].r=r; tree[id].add=0; //标记置0 if(l==r) { tree[id].sum=a[l]; return ; } int mid=(l+r)/2; build(id*2,l,mid); build(id*2+1,mid+1,r); tree[id].sum=tree[id*2].sum+tree[id*2+1].sum; //维护父节点的和值}然后我们再来看查询函数,在查询函数,保证此节点负责的区间里面有需要查询的区间,如果此节点的区间完全在查询区间里面,就说明这个区间的sum是我们需要的,返回该值,如果此节点的区间中部分区间包涵查询区间,为了查询到正确值,我们在进行递归查询下一个节点时,需要将先在的节点中的add值向下传递,因为这个节点add包涵了要对这个区间的操作,并没有往下传递,如果我们要查询的区间在下层区间中,我们就必须向下传递来更新下层区间的值,这个向下传递为pushdown,在向下传递操作完成后,要对下层的两个节点的sum值进行维护,直接用add乘以下层节点区间的长度就能轻易维护本节点的sum值。
void pushdown(int id){ if(tree[id].add!=0) { tree[id*2].add+=tree[id].add; tree[id*2+1].add+=tree[id].add; long long lsum=tree[id*2].r-tree[id*2].l+1; long long rsum=tree[id*2+1].r-tree[id*2+1].l+1; tree[id*2].sum+=lsum*tree[id].add; tree[id*2+1].sum+=rsum*tree[id].add; //维护左右节点的sum值 tree[id].add=0; //标记清0 }}
long long querysum(int id,int ql,int qr){ int l=tree[id].l; int r=tree[id].r; int mid=(l+r)/2; if(r<ql||l>qr) //不在本区间内 return 0; if(ql<=l&&qr>=r) //本区间完全在查询区间里面 return tree[id].sum; pushdown(id); //将本节点的add向下传递 if(mid>=qr) return querysum(id*2,ql,qr); else if((mid+1)<=ql) return querysum(id*2+1,ql,qr); else return querysum(id*2,ql,qr)+querysum(id*2+1,ql,qr);}
最后来看更新函数update,我们将一个要更新的区间按照mid,分为一个个小的要更新的区间,我们并不一定要走到叶子节点去更新节点的值,我们只需要更新能包涵更新区间的所有小区间的add值,有些区间我们可能并不会查询,然后我们把需要更新的节点进行pushdown往下更新。
void update(int id,int ql,int qr,int newval){ int l=tree[id].l; int r=tree[id].r; int mid=(l+r)/2; if(r<ql||qr<l) return; if(ql<=l&&qr>=r) { tree[id].add+=newval; //维护add tree[id].sum+=(r-l+1)*newval; //维护sum值 return ; } pushdown(id); //更新add if(mid>=qr) update(id*2,ql,qr,newval); else if((mid+1)<=ql) update(id*2+1,ql,qr,newval); else { update(id*2,ql,qr,newval); update(id*2+1,ql,qr,newval); } tree[id].sum=tree[id*2].sum+tree[id*2+1].sum; //当下层节点都维护好过后再来维护父节点。}
最后附上完整代码:
#include<stdio.h>#include<string.h>#include<algorithm>using namespace std;#define maxn 100005long long a[maxn];struct node{ int id; int l; int r; long long sum; long long add;}tree[maxn*4];void pushdown(int id){ if(tree[id].add!=0) { tree[id*2].add+=tree[id].add; tree[id*2+1].add+=tree[id].add; long long lsum=tree[id*2].r-tree[id*2].l+1; long long rsum=tree[id*2+1].r-tree[id*2+1].l+1; tree[id*2].sum+=lsum*tree[id].add; tree[id*2+1].sum+=rsum*tree[id].add; tree[id].add=0; }}void update(int id,int ql,int qr,int newval){ int l=tree[id].l; int r=tree[id].r; int mid=(l+r)/2; if(r<ql||qr<l) return; if(ql<=l&&qr>=r) { tree[id].add+=newval; tree[id].sum+=(r-l+1)*newval; return ; } pushdown(id); if(mid>=qr) update(id*2,ql,qr,newval); else if((mid+1)<=ql) update(id*2+1,ql,qr,newval); else { update(id*2,ql,qr,newval); update(id*2+1,ql,qr,newval); } tree[id].sum=tree[id*2].sum+tree[id*2+1].sum;}long long querysum(int id,int ql,int qr){ int l=tree[id].l; int r=tree[id].r; int mid=(l+r)/2; if(r<ql||l>qr) return 0; if(ql<=l&&qr>=r) return tree[id].sum; pushdown(id); if(mid>=qr) return querysum(id*2,ql,qr); else if((mid+1)<=ql) return querysum(id*2+1,ql,qr); else return querysum(id*2,ql,qr)+querysum(id*2+1,ql,qr);}void build(int id,int l,int r){ tree[id].l=l; tree[id].r=r; tree[id].add=0; if(l==r) { tree[id].sum=a[l]; return ; } int mid=(l+r)/2; build(id*2,l,mid); build(id*2+1,mid+1,r); tree[id].sum=tree[id*2].sum+tree[id*2+1].sum;}int main(){ long long n,q; char s[10]; scanf("%lld%lld",&n,&q); for(int i=1;i<=n;i++) scanf("%lld",&a[i]); build(1,1,n); while(q--) { long long c,b; scanf("%s%lld%lld",s,&c,&b); if(s[0]=='Q') { long long ans; ans=querysum(1,c,b); printf("%lld\n",ans); } else { long long k; scanf("%lld",&k); update(1,c,b,k); } }return 0;}
0 0
- POJ 3468 A Simple Problem with Integers(区间更新)
- POJ 3468 A Simple Problem with Integers(区间更新)
- POJ 3468 A Simple Problem with Integers(区间更新)
- POJ 3468 A Simple Problem with Integers(区间更新)
- A Simple Problem with Integers +poj+线段树区间更新
- poj 3468 A Simple Problem with Integers(线段树区间更新 or 树状数组区间更新)
- poj 3468 A Simple Problem with Integers (线段树区间更新 + 树状数组区间更新)
- Poj 3468 A Simple Problem with Integers (线段树 区间更新 区间求和)
- poj 3468 A Simple Problem with Integers经典区间更新区间查询
- 20140719 「线段树 - 区间更新,区间求和」 POJ 3468 A Simple Problem with Integers
- 20140719 「树状数组 - 区间更新,区间求和」 POJ 3468 A Simple Problem with Integers
- POJ 3468 A Simple Problem with Integers(区间更新+区间求和)
- poj 3468 A Simple Problem with Integers(区间更新 区间求和)
- poj 3468 A Simple Problem with Integers(线段树+区间更新+区间求和)
- POJ 3468 A Simple Problem with Integers (树状数组解法 树状数组区间更新 区间查询)
- POJ 3468 A Simple Problem with Integers(线段树区间更新区间查询)
- POJ 3468 A Simple Problem with Integers 数据结构+线段树+区间更新+区间求和
- POJ 3468 A Simple Problem with Integers 区间和更新,区间和查找
- 使用Visio画UML模型
- NPOI创建DOCX常用操作
- 2268: SB_cyh and his BST two (treap&&set)
- Java集合总结
- Oozie重装遇到错误Error:DB schema exists
- POJ 3468 A Simple Problem with Integers(区间更新)
- Shader的学习方法总结
- java过滤Emoji表情
- SSL
- Node.js函数传递之基础HTTP请求
- 简单的短信验证
- EditText失去焦点时,键盘收起的布局
- Mysql 访问权限
- 22. ubuntu 16.04 LTS 安装mongodb 3.2.8