http://codevs.cn/problem/1082/
在这道题因为数据类型卡了我1个多小时之后,我终于把它干掉了(洛谷3372也可以用这道题的代码过,复制过去改一下读入顺序就行,目测codevs的数据比较毒瘤)
树状数组 区间修改+区间查询
实在是喜欢树状数组啊!好理解,更重要是好写啊!这次写写区间修改区间查询哈
首先还是上次区间修改单点查询用过的差分思想,我们先搞一个c数组作为差分数组(不懂的去看我的上一个博客好了,实在懒得列表了)
简单可证,
那么可以得到以下式子
a[1]+a[2]+...+a[i]
=c[1]+(c[1]+c[2])+...+(c[1]+c[2]+...+c[i])
=i*c[1]+(i-1)*c[2]+...+c[i]
=i*(c[1]+c[2]+...+c[i])-1*c[2]-...-(i-1)*c[i]
于是,我们再搞一个数组c1
那之前的式子就可以表示为
然后再搞两个树状数组来分别维护一下c数组和c1数组的区间和就ok了
下面贴的是codevs1082的AC代码,这是一道线段树的模板题,裸题
(这里b数组是c的树状数组,bb数组是c1数组的树状数组,然后因为懒,所以函数直接复制了一下,不太美观哈)
#include<bits/stdc++.h>
using namespace std;
long long n,m,a[200010],b[200010],c[200010],bb[200010],c1[200010];
long long lowbit(long long x)
{
return x&-x;
}
void modify(int x,long long y)
{
for (int i=x;i<=n;i+=lowbit(i))
b[i]+=y;
}
long long query(long long x)
{
long long ans=0;
for (int i=x;i>0;i-=lowbit(i))
ans+=b[i];
return ans;
}
void modifyy(long x,long long y)
{
for (int i=x;i<=n;i+=lowbit(i))
bb[i]+=y;
}
long long queryy(long long x)
{
long long ans=0;
for (int i=x;i>0;i-=lowbit(i))
ans+=bb[i];
return ans;
}
int main()
{
cin>>n;
for (int i=1;i<=n;i++)
{
cin>>a[i];
c[i]=a[i]-a[i-1];
c1[i]=(i-1)*c[i];
}
for (int i=1;i<=n;i++)
modify(i,c[i]);
for (int i=1;i<=n;i++)
modifyy(i,c1[i]);
cin>>m;
for (int i=1;i<=m;i++)
{
long long p;
cin>>p;
if (p==1)
{
long long xx,yy,zz;
cin>>xx>>yy>>zz;
modify(xx,zz);
modify(yy+1,-zz);
modifyy(xx,(xx-1)*zz);
modifyy(yy+1,-yy*zz);
}
if (p==2)
{
long long xx,yy,ss;
cin>>xx>>yy;
ss=(yy*query(yy)-queryy(yy))-((xx-1)*query(xx-1)-queryy(xx-1));
cout<<ss<<endl;
}
}
return 0;
}
友情提醒,做这道题的时候一定要开longlong,这个事情卡了我1个多小时%%%%
我写代码的时候一顺手就写了个cin cout……这道题没啥事,但平时还是要写scanf的
树状数组大法好!!!