题目描述
有一天小妖精们又在做游戏。这个游戏是这样的。
妖精仓库的储物点可以看做在一个数轴上。每一个储物点会有一些东西,同时他们之间存在距离。
每次他们会选出一个小妖精,然后剩下的人找到区间[l,r]储物点的所有东西,清点完毕之后问她,把这个区间内所有储物点的东西运到另外一个仓库的代价是多少?
比如储物点i有x个东西,要运到储物点j,代价为
x
×
d
i
s
t
(
i
,
j
)
x \times \mathrm{dist}( i , j )
x×dist(i,j)
dist就是仓库间的距离。
当然啦,由于小妖精们不会算很大的数字,因此您的答案需要对19260817取模。
输入格式:
第一行两个数表示n,m
第二行n-1个数,第ii个数表示第ii个储物点与第i+1个储物点的距离
第三行n个数,表示每个储物点的东西个数
之后m行每行三个数x l r
表示查询要把区间[l,r]储物点的物品全部运到储物点x的花费
输出格式:
对于每个询问输出一个数表示答案
说明
对于30%的数据,n,m≤1000
对于另外20%的数据,所有储物点间的距离都为1
对于另外20%的数据,所有储物点的物品数都为1
对于100%的数据 ,
n
,
m
≤
200000
;
a
i
,
b
i
<
=
2
⋅
1
0
9
n , m \le 200000 ; a_i , b_i <= 2\cdot 10^9
n,m≤200000;ai,bi<=2⋅109
题目分析
参考了luogu题解某dalao
s
u
m
D
[
i
]
sumD[i]
sumD[i]记录从
i
i
i到
1
1
1的距离
s
u
m
A
[
i
]
sumA[i]
sumA[i]是物品数量
a
[
i
]
a[i]
a[i]的前缀和
s
u
m
D
A
[
i
]
sumDA[i]
sumDA[i]记录
s
u
m
D
[
i
]
∗
a
[
i
]
sumD[i]*a[i]
sumD[i]∗a[i]的前缀和
对于每次询问区间我们拆成两个小区间
[
l
l
,
x
−
1
]
,
[
x
+
1
,
r
r
]
[ll,x-1],[x+1,rr]
[ll,x−1],[x+1,rr]
以左边这个为例,其运输总费用为
∑
i
=
l
l
x
−
1
(
s
u
m
D
[
x
]
−
s
u
m
D
[
i
]
)
∗
a
[
i
]
\sum_{i=ll}^{x-1}(sumD[x]-sumD[i])*a[i]
∑i=llx−1(sumD[x]−sumD[i])∗a[i]
∑
i
=
l
l
x
−
1
s
u
m
D
[
x
]
∗
a
[
i
]
−
s
u
m
D
[
i
]
∗
a
[
i
]
\sum_{i=ll}^{x-1}sumD[x]*a[i]-sumD[i]*a[i]
∑i=llx−1sumD[x]∗a[i]−sumD[i]∗a[i]
s
u
m
D
[
x
]
∑
i
=
l
l
x
−
1
a
[
i
]
−
∑
i
=
l
l
x
−
1
s
u
m
D
[
i
]
∗
a
[
i
]
sumD[x]\sum_{i=ll}^{x-1}a[i]-\sum_{i=ll}^{x-1}sumD[i]*a[i]
sumD[x]∑i=llx−1a[i]−∑i=llx−1sumD[i]∗a[i]
s
u
m
D
[
x
]
∗
(
s
u
m
A
[
x
−
1
]
−
s
u
m
A
[
l
l
−
1
]
)
−
(
s
u
m
D
A
[
x
−
1
]
−
s
u
m
D
A
[
l
l
−
1
]
)
sumD[x]*(sumA[x-1]-sumA[ll-1])-(sumDA[x-1]-sumDA[ll-1])
sumD[x]∗(sumA[x−1]−sumA[ll−1])−(sumDA[x−1]−sumDA[ll−1])
对于右边的区间用同样的方法推导发现就是对上面这个答案取个反
(
s
u
m
D
A
[
x
−
1
]
−
s
u
m
D
A
[
l
l
−
1
]
)
−
s
u
m
D
[
x
]
∗
(
s
u
m
A
[
x
−
1
]
−
s
u
m
A
[
l
l
−
1
]
)
(sumDA[x-1]-sumDA[ll-1])-sumD[x]*(sumA[x-1]-sumA[ll-1])
(sumDA[x−1]−sumDA[ll−1])−sumD[x]∗(sumA[x−1]−sumA[ll−1])
也就是说记录三个前缀和就可以
O
(
1
)
O(1)
O(1)查询了
#include<iostream>
#include<vector>
#include<algorithm>
#include<queue>
#include<cstring>
#include<cstdio>
using namespace std;
typedef long long lt;
lt read()
{
lt f=1,x=0;
char ss=getchar();
while(ss<'0'||ss>'9'){if(ss=='-')f=-1;ss=getchar();}
while(ss>='0'&&ss<='9'){x=x*10+ss-'0';ss=getchar();}
return f*x;
}
const int mod=19260817;
const int maxn=200010;
int n,m;
lt d[maxn],a[maxn];
lt sumD[maxn],sumA[maxn],sumDA[maxn];
lt qsum(int x,int ll,int rr,int f){
if(ll>rr) return 0;
lt res=sumD[x]%mod*(sumA[rr]-sumA[ll-1])%mod-(sumDA[rr]-sumDA[ll-1])%mod;
return (res*f%mod+mod)%mod;
}
int main()
{
n=read();m=read();
for(int i=2;i<=n;++i) d[i]=read()%mod;
for(int i=1;i<=n;++i)
{
a[i]=read()%mod;
sumA[i]=(sumA[i-1]+a[i])%mod;
sumD[i]=(sumD[i-1]+d[i])%mod;
sumDA[i]=(sumDA[i-1]+a[i]*sumD[i])%mod;
}
while(m--)
{
int x=read(),ll=read(),rr=read();
lt ansl=qsum(x,ll,min(rr,x-1),1);
lt ansr=qsum(x,max(ll,x+1),rr,-1);
printf("%lld\n",(ansl+ansr)%mod);
}
return 0;
}