您的位置:首页 > 理论基础 > 数据结构算法

POJ3469

2016-05-30 11:52 429 查看
线段树解法:

本题需要成段更新区间,所以 为了保护线段树的高效,对每个节点,我们维护一下两个数据。

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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  数据结构