链接:P3655
题目有点复杂,直接点链接吧。
有水团awa
虽然难度只有黄色,但是我还是来做了这道树状数组水题awa
对于题目中的对于x到z的成员都加上一个值z,当时脑子里飘过的想法,不是线段树就树状数组(因为俺只会这两个)
因为用线段树应该也可以做,时间急促我以后会慢慢补的。
这里先主要说一下我利用树状数组写的过程
树状数组维护一个差分数组进行区间修改区间求和
然后对于魅力值,我们可以首先算出原本一开始的魅力值,对于每一次的修改,
我们可以发现,如果区间加减之后,根据魅力值计算的公式,在区间内部的相邻的魅力值不会改变。我们只需要判断区间两边边界的差值的改变即可。
例如对于一个区间[x,y],我们先来把没有加上z值的x-1和x的差值算出来,再把y+1和y的差值算出来。然后利用树状数组加上z值,再把这个时候x-1和x的差值、y+1和y的差值算出来。
这时候总的魅力值就是把之前改变的魅力值还原加上当前情况下改变的魅力值
具体的看代码,确实…难以形容清楚(我的表达能力需要提升)
代码如下:
#include <cstdio>
#include <iostream>
#define LL long long
using namespace std;
int a[400001],n,m,s,t;
LL aa[400001],ans;
int lowbit (int x)
{
return x&-x;
}
void add(int x,LL v)
{
while (x<=n)
{
aa[x]+=v;
x+=lowbit(x);
}
} //树状数组基本操作
LL pd(int x)
{
LL ans=0;
while (x>=1)
{
ans+=aa[x];
x-=lowbit(x);
}
return ans;
} //树状数组基本操作
LL check(LL x)
{
if (x>0)
return -s*x;
else
return -t*x;
} //根据魅力值公式定义来计算
int main()
{
scanf("%d%d%d%d",&n,&m,&s,&t);
int k=0;
int x;
scanf("%d",&x);
a[0]=0;
for (int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
add(i,a[i]-a[i-1]); //用树状数组维护一个差分数组
ans+=check(a[i]-a[i-1]); //先把一开始的魅力值算出来
}
for (int i=1;i<=m;i++)
{
int x,y,z;
scanf("%d%d%d",&x,&y,&z);
LL a1=pd(x)-pd(x-1);
LL b1=pd(y+1)-pd(y); //算出来没加上z之前的区间边界差分值
add(x,z);
if (y!=n)
add(y+1,-z); //区间修改
LL a2=pd(x)-pd(x-1);
LL b2=pd(y+1)-pd(y); //算出来加上z之后的区间边界差分值
ans=ans-check(a1)+check(a2); //把之前改变的魅力值还原加上当前情况下的魅力值
if (y!=n)
ans=ans-check(b1)+check(b2);
printf("%lld\n",ans);
}
return 0;
}