POJ 3468 A Simple Problem with Integers(线段树 or 树状数组—区间求和,成段更新)
2015-10-30 18:59
399 查看
A Simple Problem with Integers
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 Input
Sample Output
题意:给出一个含有n个整数的数列,C a b c表示在数列中从第a个元素到第b个元素值都增加c,Q a b表示从第a个数到第b个数相加,并输出所得值。
题解:很明显的区间求和问题,用线段树解,不能一次只更新区间内一个点,明显会超时,可以给每个节点加一个temp量来记录增量的累加。QAQ,根本不懂,倒腾了两天,最后照着匡斌的代码才A的。线段树必须重看
代码如下:
2016/3/22更新:
成段更新要用到懒惰标记(lazy思想,延迟更新)。之前一直没认真看lazy思想,今天找到一篇不错的博文讲述Lazy思想: Lazy思想
代码如下:
树状数组解法:
Time Limit: 5000MS | Memory Limit: 131072K | |
Total Submissions: 81443 | Accepted: 25160 | |
Case Time Limit: 2000MS |
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 Input
10 5 1 2 3 4 5 6 7 8 9 10 Q 4 4 Q 1 10 Q 2 4 C 3 6 3 Q 2 4
Sample Output
4 55 9 15
题意:给出一个含有n个整数的数列,C a b c表示在数列中从第a个元素到第b个元素值都增加c,Q a b表示从第a个数到第b个数相加,并输出所得值。
题解:很明显的区间求和问题,用线段树解,不能一次只更新区间内一个点,明显会超时,可以给每个节点加一个temp量来记录增量的累加。QAQ,根本不懂,倒腾了两天,最后照着匡斌的代码才A的。线段树必须重看
代码如下:
#include<cstdio> int a[100000+100]; struct node { int left,right; __int64 temp; __int64 sum; }num[400010]; __int64 build(int left,int right,int cnt) { int mid; num[cnt].left=left; num[cnt].right=right; num[cnt].temp=0; num[cnt].sum=0; if(left==right) return num[cnt].sum=a[left]; mid=(left+right)>>1; return num[cnt].sum=build(left,mid,cnt*2)+build(mid+1,right,cnt*2+1); } void update(int left,int right,__int64 count,int cnt) { int mid; if(left==num[cnt].left&&right==num[cnt].right) { num[cnt].temp+=count; return ; } num[cnt].sum+=count*(right-left+1); mid=(num[cnt].left+num[cnt].right)>>1; if(right<=mid) update(left,right,count,cnt*2); else if(left>mid) update(left,right,count,cnt*2+1); else { update(left,mid,count,cnt*2); update(mid+1,right,count,cnt*2+1); } } __int64 query(int left,int right,int cnt) { int mid; if(left==num[cnt].left&&num[cnt].right==right) return num[cnt].sum+(right-left+1)*num[cnt].temp; mid=(num[cnt].left+num[cnt].right)>>1; num[cnt].sum+=(num[cnt].right-num[cnt].left+1)*num[cnt].temp; update(num[cnt].left,mid,num[cnt].temp,cnt*2); update(mid+1,num[cnt].right,num[cnt].temp,cnt*2+1); num[cnt].temp=0; if(right<=mid) return query(left,right,cnt*2); else if(left>mid) return query(left,right,cnt*2+1); else return query(left,mid,cnt*2)+query(mid+1,right,cnt*2+1); } int main() { int N,Q,n,m,i,count; char s[2]; while(scanf("%d%d",&N,&Q)!=EOF) { for(i=1;i<=N;i++) scanf("%d",&a[i]); build(1,N,1); while(Q--) { scanf("%s",s); if(s[0]=='C') { scanf("%d%d%d",&n,&m,&count); update(n,m,count,1); } else { scanf("%d%d",&n,&m); printf("%I64d\n",query(n,m,1)); } } } return 0; }
2016/3/22更新:
成段更新要用到懒惰标记(lazy思想,延迟更新)。之前一直没认真看lazy思想,今天找到一篇不错的博文讲述Lazy思想: Lazy思想
代码如下:
#include<cstdio> #include<cstring> #include<algorithm> using namespace std; #define maxn 100010 #define LL long long #define lson i*2,l,m #define rson i*2+1,m+1,r LL sum[maxn*4]; LL addv[maxn*4]; void PushDown(int i,int num) { if(addv[i]) { sum[i*2]+=addv[i]*(num-(num/2)); sum[i*2+1]+=addv[i]*(num/2); addv[i*2]+=addv[i]; addv[i*2+1]+=addv[i]; addv[i]=0; } } void PushUp(int i) { sum[i]=sum[i*2+1]+sum[i*2]; } void build(int i,int l,int r) { addv[i]=0; if(l==r) { scanf("%I64d",&sum[i]); return ; } int m=(l+r)/2; build(lson); build(rson); PushUp(i); } void update(int ql,int qr,int add,int i,int l,int r) { if(ql<=l&&r<=qr) { addv[i]+=add; sum[i]+=(LL)add*(r-l+1); return ; } PushDown(i,r-l+1); int m=(l+r)/2; if(ql<=m) update(ql,qr,add,lson); if(qr>m) update(ql,qr,add,rson); PushUp(i); } LL query(int ql,int qr,int i,int l,int r) { if(ql<=l&&r<=qr) return sum[i]; PushDown(i,r-l+1); int m=(l+r)/2; LL ans=0; if(ql<=m) ans+=query(ql,qr,lson); if(m<qr) ans+=query(ql,qr,rson); return ans; } int main() { int n,q,x,y,z; char s[5]; while(scanf("%d%d",&n,&q)!=EOF) { build(1,1,n); while(q--) { scanf("%s",s); if(s[0]=='C') { scanf("%d%d%d",&x,&y,&z); update(x,y,z,1,1,n); } else { scanf("%d%d",&x,&y); printf("%I64d\n",query(x,y,1,1,n)); } } } return 0; }
树状数组解法:
#include<cstdio> #include<cstring> #define maxn 100010 #define LL long long LL bit1[maxn],bit2[maxn]; int n,q; LL sum(LL *b, int i) { LL ans = 0; while(i > 0) { ans += b[i]; i -= i & -i; } return ans; } void add(LL *b, int i, int x) { while(i <= n) { b[i] += x; i += i & -i; } } int main() { int x, y, i; LL a, z; char s[5]; while(scanf("%d%d",&n,&q)!=EOF) { for(i = 1; i <= n; ++i) { scanf("%I64d",&a); add(bit1, i, a); } while(q--) { scanf("%s",s); if(s[0] == 'C') { scanf("%d%d%I64d",&x, &y, &z); add(bit1, x, -z * (x - 1) ); add(bit2, x, z); add(bit1, y + 1, z * y); add(bit2, y + 1, -z); } else { scanf("%d%d",&x, &y); LL ans = 0; ans += sum(bit1, y) + sum(bit2, y) * y; ans -= sum(bit1, x-1) + sum(bit2, x-1) * (x - 1); printf("%I64d\n",ans); } } } return 0; }
相关文章推荐
- utf-8的中文:一个汉字占三个字节长度
- cpu调度
- EditTable-V1.0--续集
- 87. Scramble String (String; DP)
- 华为认证和思科认证,哪一款适合你?
- STL-综合示例
- STL-泛型算法示例
- STL-初始化实验
- STL-访问向量信息
- STL-向量插入/删除
- STL-vector中reserve和resize的区…
- STL-list的访问与遍历
- STL-list插入与删除
- STL-list成员的删除
- STL-list存储格式探究
- STL-list中的spilce()
- STL-list中的merge()
- STL-stack
- STL-单向队列queue
- FTM的PWM、输入捕获、正交解码