codeforces 1053C Putting Boxes Together
题意:
给你一个数组
a
a
a,
a
i
a_i
ai代表第
i
i
i个元素放在第
a
i
a_i
ai个箱子里面。并且,对于第i个元素,从一个箱子移动到相邻的箱子需要花费
w
i
w_i
wi点精力。现在有两个操作:
1.把第i个元素移动的花费变为x
2.查询[L,R]区间内的元素按原有元素顺序移动到任意连续区间[x,x+(r-l)]的最小花费。
题解:
我们看一下移动到[x,x+(r-l)]的花费:
c
o
s
t
=
∑
i
=
l
r
w
i
∗
∣
a
x
−
a
i
+
i
−
x
∣
=
∑
i
=
l
r
w
i
∗
∣
a
x
−
x
−
(
a
i
−
i
)
∣
=
∑
i
=
l
r
w
i
∗
∣
b
x
−
b
i
∣
cost = \sum_{i=l}^{r}{w_{i}*\left|a_x-a_i+i-x\right|} \newline= \sum_{i=l}^{r}{w_{i}*\left|a_x-x-(a_i-i)\right|} \newline= \sum_{i=l}^{r}{w_{i}*\left|b_x-b_i\right|}
cost=i=l∑rwi∗∣ax−ai+i−x∣=i=l∑rwi∗∣ax−x−(ai−i)∣=i=l∑rwi∗∣bx−bi∣
有了这个转化之后我们可以发现这明显的就是带权中位数嘛。也就是说我们只要维护区间中位数就行了,而区间中位数可以由
w
w
w的区间和求出来,那么用树状数组来维护吗,然后再二分就行了。同时,也要用一个树状数组来维护区间
w
i
∗
a
i
w_i*a_i
wi∗ai的值,这样这题就做完啦。
#include<bits/stdc++.h>
const int mod=1e9+7;
const int maxn=2e5+7;
int n,q,a[maxn],w[maxn];
typedef long long ll;
struct Fenwick1
{
ll bs[maxn];
void add(int x,ll y)
{
for(;x<=n;x+=x&-x) bs[x]+=y;
}
ll sum(int x)
{
ll s=0;
for(;x>=1;x-=x&-x) s+=bs[x];
return s;
}
}B0;
struct Fenwick
{
int bs[maxn];
void add(int x,int y)
{
for(;x<=n;x+=x&-x) (bs[x]+=y)%=mod;
}
ll sum(int x)
{
int s=0;
for(;x>=1;x-=x&-x) (s+=bs[x])%=mod;
return s;
}
}B1;
int main()
{
scanf("%d%d",&n,&q);
for(int i=1;i<=n;++i)
scanf("%d",a+i),a[i]-=i;
for(int i=1;i<=n;++i) scanf("%d",w+i);
for(int i=1;i<=n;++i)
B0.add(i,w[i]),
B1.add(i,w[i]*1ll*a[i]%mod);
while(q--)
{
int x,y;
scanf("%d%d",&x,&y);
if(x<0)
{
x=-x; int dt=y-w[x];
w[x]=y; B0.add(x,dt);
B1.add(x,dt*1ll*a[x]%mod);
}
else
{
ll sl=B0.sum(x-1),
su=B0.sum(y)-sl;
su=(su+1)/2;
int l=x,r=y;
while(l<r)
{
int m=(l+r)>>1;
if(B0.sum(m)-sl>=su) r=m;
else l=m+1;
}
int m=l;
//mid pos is m
ll ans=
(B1.sum(y)-B1.sum(m))-(B0.sum(y)-B0.sum(m))%mod*1ll*(a[m])%mod
-(B1.sum(m)-B1.sum(x-1))+(B0.sum(m)-B0.sum(x-1))%mod*(a[m])%mod;
ans=(ans%mod+mod)%mod;
printf("%d\n",int(ans));
}
}
}