POJ3469
2016-05-30 11:52
429 查看
线段树解法:
本题需要成段更新区间,所以 为了保护线段树的高效,对每个节点,我们维护一下两个数据。
a.给这个节点对应的区间内的所有原始共同加上的值。
b.在这个节点对应的区间中除去a之外其他的值的和。
通过单独维护共同加上的值,给区间同时加上一个值的操作就可以高效的进行了。如果对于父亲节点同时加上一个值,那么这个值就不会在儿子节点被重复考虑。
树状数组解法:
如果给区间[l,r)同时加上x每个节点的值将会
令 s(i) = 加上x之前的sigma(a[j])
s’[i] = 加上x之后的sigma(a[j])
那么就有 i < l 时s’[i] = s[i]
l<= i <=r 时 s’[i] = s[i] +x*(i-l+1)
= s[i] +x*l -x*(l-1)
r < i 时 s’[i] = s[i] +x(r-l +1)
下面记 sum(bit,i)为树状数组的前i项和。我们可以构建两个B树状数组bit0,bit1。
并且设
sigma(a[j]) = sum(bit1,i) *i + sum(bit0,i)
那么在[l,r) 区间上同时加上x就可以看成是
1.在bit0的L位置上加上-x(l-1)
2.在bit1的L位置上加上x
3.在bit0的R+1位置上加上XR
4.在bit1的R+1位置上加上-x
本题需要成段更新区间,所以 为了保护线段树的高效,对每个节点,我们维护一下两个数据。
a.给这个节点对应的区间内的所有原始共同加上的值。
b.在这个节点对应的区间中除去a之外其他的值的和。
通过单独维护共同加上的值,给区间同时加上一个值的操作就可以高效的进行了。如果对于父亲节点同时加上一个值,那么这个值就不会在儿子节点被重复考虑。
#include<iostream> #include<algorithm> #include<cstdio> #include<queue> #include<set> #include<map> #include<cstring> #include<string> #include<cmath> #include<ctime> using namespace std; typedef long long LL; typedef pair<int,int> pii; const int MAXN = 1E5 + 10; const int INF = 1E9; const int dat_size = 4*MAXN; //输入 int n,q; int A[MAXN]; char t[MAXN]; int L[MAXN],R[MAXN]; int X[MAXN]; //线段树 LL s1[4*MAXN],s2[4*MAXN]; //对区间[a,b)同时加x void add(int a, int b,int x,int k,int l,int r) { if(a<=l&&r<=b) { s1[k] += x; }else if(l<b&&r>a) { s2[k] += (min(b,r)-max(a,l))*x; add(a,b,x,k*2+1,l,(l+r)/2); add(a,b,x,k*2+2,(l+r)/2,r); } } LL sum(int a,int b,int k,int l,int r) { if(b<=l||a>=r) { return 0; } else if(a <= l && r <=b) { return s1[k]*(r-l) +s2[k]; } else { LL res = (min(b,r)-max(a,l))*s1[k]; res += sum(a,b,k*2+1,l,(l+r)/2); res += sum(a,b,k*2+2,(l+r)/2,r); return res; } } void solve() { for(int i=0 ;i<n; i++) { add(i,i+1,A[i],0,0,n); } for(int i = 0 ;i < q ; i++) { if(t[i] == 'C') { add(L[i]-1,R[i],X[i],0,0,n); } else { printf("%lld\n",sum(L[i]-1,R[i],0,0,n)); } } } int main() { scanf("%d%d",&n,&q); for(int i=0;i<n;i++) { scanf("%d",&A[i]); } for(int i=0;i<q;i++) { scanf(" %c ",&t[i]); if(t[i]=='C') { scanf("%d%d%d",&L[i],&R[i],&X[i]); } else { scanf("%d%d",&L[i],&R[i]); } } solve(); return 0; }
树状数组解法:
如果给区间[l,r)同时加上x每个节点的值将会
令 s(i) = 加上x之前的sigma(a[j])
s’[i] = 加上x之后的sigma(a[j])
那么就有 i < l 时s’[i] = s[i]
l<= i <=r 时 s’[i] = s[i] +x*(i-l+1)
= s[i] +x*l -x*(l-1)
r < i 时 s’[i] = s[i] +x(r-l +1)
下面记 sum(bit,i)为树状数组的前i项和。我们可以构建两个B树状数组bit0,bit1。
并且设
sigma(a[j]) = sum(bit1,i) *i + sum(bit0,i)
那么在[l,r) 区间上同时加上x就可以看成是
1.在bit0的L位置上加上-x(l-1)
2.在bit1的L位置上加上x
3.在bit0的R+1位置上加上XR
4.在bit1的R+1位置上加上-x
#include<iostream> #include<algorithm> #include<cstdio> #include<cstring> #include<string> #include<queue> #include<map> #include<set> #include<cmath> using namespace std; const int maxn = 1e5 + 10; typedef long long LL; //输入 int n,q; int A[maxn]; char T[maxn]; int L[maxn],R[maxn],X[maxn]; //BIT; LL bit0[maxn],bit1[maxn]; LL sum(LL *b,int i) { LL s = 0; while(i > 0) { s += b[i]; i -= i&-i; } return s; } void add(LL *b,int i,int v) { while(i <= n) { // cout<<-1<<endl; b[i] += v; i += i&-i; } } void solve() { for(int i=1;i<=n;i++) { add(bit0,i,A[i]); } for(int i=1;i<=q;i++) { if(T[i]=='C') { add(bit0,L[i],-X[i]*(L[i]-1)); add(bit1,L[i],X[i]); add(bit0,R[i]+1,X[i]*R[i]); add(bit1,R[i]+1,-X[i]); } else { LL res = 0; res += sum(bit0,R[i]) + sum(bit1,R[i])*R[i]; res -= sum(bit0,L[i]-1) + sum(bit1,L[i]-1)*(L[i]-1); printf("%lld\n",res); } } } int main() { scanf("%d%d",&n,&q); for(int i=1;i<=n;i++) { scanf("%d",&A[i]); } for(int i=1;i<=q;i++) { scanf(" %c ",&T[i]); if(T[i]=='C') { scanf("%d%d%d",&L[i],&R[i],&X[i]); }else{ scanf("%d%d",&L[i],&R[i]); } } solve(); return 0; }
相关文章推荐
- C#数据结构之顺序表(SeqList)实例详解
- Lua教程(七):数据结构详解
- 解析从源码分析常见的基于Array的数据结构动态扩容机制的详解
- C#数据结构之队列(Quene)实例详解
- C#数据结构揭秘一
- C#数据结构之单链表(LinkList)实例详解
- 数据结构之Treap详解
- 用C语言举例讲解数据结构中的算法复杂度结与顺序表
- C#数据结构之堆栈(Stack)实例详解
- C#数据结构之双向链表(DbLinkList)实例详解
- JavaScript数据结构和算法之图和图算法
- Java数据结构及算法实例:冒泡排序 Bubble Sort
- Java数据结构及算法实例:插入排序 Insertion Sort
- Java数据结构及算法实例:考拉兹猜想 Collatz Conjecture
- java数据结构之java实现栈
- java数据结构之实现双向链表的示例
- Java数据结构及算法实例:选择排序 Selection Sort
- Java数据结构及算法实例:朴素字符匹配 Brute Force
- Java数据结构及算法实例:汉诺塔问题 Hanoi
- Java数据结构及算法实例:快速计算二进制数中1的个数(Fast Bit Counting)