poj 3468 A Simple Problem with Integers(线段树+树状数组区间更新区间查询)
来源:互联网 发布:百度网盘mac版怎么安装 编辑:程序博客网 时间:2024/04/29 12:05
A Simple Problem with Integers
Time Limit: 5000MS Memory Limit: 131072K
Total Submissions: 122283 Accepted: 37929
Case Time Limit: 2000MS
Description
You have N integers, A1, A2, … , AN. You need to deal with two kinds of operations. One type of operation is to add some given number to each number in a given interval. The other is to ask for the sum of numbers in a given interval.
Input
The first line contains two numbers N and Q. 1 ≤ N,Q ≤ 100000.
The second line contains N numbers, the initial values of A1, A2, … , AN. -1000000000 ≤ Ai ≤ 1000000000.
Each of the next Q lines represents an operation.
“C a b c” means adding c to each of Aa, Aa+1, … , Ab. -10000 ≤ c ≤ 10000.
“Q a b” means querying the sum of Aa, Aa+1, … , Ab.
Output
You need to answer all Q commands in order. One answer in a line.
Sample Input10 51 2 3 4 5 6 7 8 9 10Q 4 4Q 1 10Q 2 4C 3 6 3Q 2 4Sample Output455915HintThe sums may exceed the range of 32-bit integers.
树状数组
分析:
首先不考虑原始的情况,我们只考虑区间更新过后带来的影响的话,首先对于询问一个区间当中的元素和的话,肯定就是这个区间的原始的元素和,加上区间更新后所带来的影响,所以我们用a[]数组来保存前i个元素的和。
然后考虑区间更新所带来的影响,采用差分的思想,
设原数组第i位的值为ai,di=ai−a[i−1],则有(这里认为a0=0,此时的a表示的是数组中的原始值,与代码中的a不一样):
所以有:
于是我们把原数组差分后维护两个树状数组,一个维护di,一个维护di×i。
这样区间求和时可以在两个树状数组中查询得到前缀和,区间修改时就是差分数组的修改,每次修改两个点即可。
其中c[i]维护的是d[i],c1[i]维护的是d[i]×i。
但是这里的c[]和c1[]都是差分数组,保存的也就只是更新所带来的值的变化,但因为这里要求的是在原来的基础上更新后的区间和,所以最终还要加上最原始的区间和。
#include<iostream>#include<algorithm>#include<cstdio>#include<cstring>using namespace std;long long int a[510000],c[510000],cc[510000];int n,m;int lowbit(int x){ return x&(-x);}void update(long long int x,long long int v){ for(long long int i=x;i<=n;i+=lowbit(i)) { c[i]+=v; cc[i]+=(long long )x*v; }}long long int sum(long long int x){ long long int ans=0; for(int i=x;i;i-=lowbit(i)) ans+=(x+1)*c[i]-cc[i]; return ans+a[x];}int main(){ char ch; long long int s,r,va,num; while(scanf("%d%d",&n,&m)!=EOF) { memset(a,0,sizeof(a)); memset(c,0,sizeof(c)); memset(cc,0,sizeof(cc)); for(int i=1;i<=n;i++) { scanf("%lld",&num); a[i]+=a[i-1]+num; } for(int i=0;i<m;i++) { getchar(); scanf("%c",&ch); if(ch=='Q') { scanf("%lld%lld",&s,&r); printf("%lld\n",sum(r)-sum(s-1)); } else { scanf("%lld%lld%lld",&s,&r,&va); update(s,va); update(r+1,-va); } } } return 0;}
线段树:
#include<iostream>#include<algorithm>#include<cstdio>#include<cstring>using namespace std;struct node{ long long int sum,va;}no[300000];void pu(int t){ no[t].sum=no[t<<1].sum+no[t<<1|1].sum;}void build(int l,int r,int s){ no[s].va=0; if(l==r) { scanf("%lld",&no[s].sum); return ; } int mid=(l+r)>>1; build(l,mid,s<<1); build(mid+1,r,s<<1|1); pu(s);}void dd(int t,int m){ if(no[t].va) { no[t<<1].va+=no[t].va; no[t<<1|1].va+=no[t].va; no[t<<1].sum+=(long long int)(m-(m>>1))*no[t].va; no[t<<1|1].sum+=(long long int)(m>>1)*no[t].va; no[t].va=0; }}long long int query(int l,int r,int ll,int rr,int s){ if(l<=ll&&rr<=r) return no[s].sum; int mid=(ll+rr)>>1; dd(s,rr-ll+1); long long int ans=0; if(l<=mid) ans+=query(l,r,ll,mid,s<<1); if(r>mid) ans+=query(l,r,mid+1,rr,s<<1|1); return ans;}void up(int l,int r,int add,int ll,int rr,int t){ if(l<=ll&&rr<=r) { no[t].sum+=(long long int )add*(rr-ll+1); no[t].va+=add; return ; } dd(t,rr-ll+1); int mid=(ll+rr)>>1; if(l<=mid) up(l,r,add,ll,mid,t<<1); if(mid<r) up(l,r,add,mid+1,rr,t<<1|1); pu(t);}int main(){ int n,q,a,b; long long int c; scanf("%d%d",&n,&q); build(1,n,1); char s[3]; while(q--) { scanf("%s",s); if(s[0]=='Q') { cin>>a>>b; cout<<query(a,b,1,n,1)<<endl; } else if(s[0]=='C') { cin>>a>>b>>c; up(a,b,c,1,n,1); } } return 0;}
- poj 3468 A Simple Problem with Integers(线段树+树状数组区间更新区间查询)
- 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 树状数组(区间更新,区间查询)
- POJ 3468 A Simple Problem with Integers 线段树(区间更新,查询,lazy数组)
- 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(线段树 or 树状数组—区间求和,成段更新)
- 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 A Simple Problem with Integers (线段树区间更新区间查询模板)
- Ubuntu下安装部署Redis,并设置远程访问和密码
- mongo-java-driver -3.2.2学习笔记-09-driver-async
- kubeadm1.8.4安装kubernetes1.8.4集群
- [测试]Linux查看和结束进程命令详解
- 倒三角形(triangle)
- poj 3468 A Simple Problem with Integers(线段树+树状数组区间更新区间查询)
- BZOJ1027 [HNOI2004]打鼹鼠 【dp】
- LeetCode--Maximum Depth of Binary Tree (检索二叉树的最大深度)Python
- 简单修复360安全检测提示的发现robots文件漏洞
- pig 笔记
- 卡巴斯基发布安全公告:2018年威胁预测
- Python 条件和循环
- redis位图法统计活跃用户
- nginx 禁止访问.svn的目录