题目描述
妖精仓库里生活着黄金妖精们,她们过着快乐,却随时准备着迎接死亡的生活。
换用更高尚的说法,是随时准备着为这个无药可救的世界献身。
然而孩子们的生活却总是无忧无虑的,幼体的黄金妖精们过着天真烂漫的生活,自然也无暇考虑什么拯救世界之类的重任。
有一天小妖精们又在做游戏。这个游戏是这样的。
妖精仓库的储物点可以看做在一个数轴上。每一个储物点会有一些东西,同时他们之间存在距离。
每次他们会选出一个小妖精,然后剩下的人找到区间[l,r][l,r]储物点的所有东西,清点完毕之后问她,把这个区间内所有储物点的东西运到另外一个仓库的代价是多少?
比如储物点ii有xx个东西,要运到储物点jj,代价为
x \times \mathrm{dist}( i , j )x×dist(i,j)
dist就是仓库间的距离。
当然啦,由于小妖精们不会算很大的数字,因此您的答案需要对19260817取模。
输入格式:
第一行两个数表示n,mn,m
第二行n-1n−1个数,第ii个数表示第ii个储物点与第i+1i+1个储物点的距离
第三行nn个数,表示每个储物点的东西个数
之后mm行每行三个数x l r
表示查询要把区间[l,r][l,r]储物点的物品全部运到储物点x的花费
输出格式:
对于每个询问输出一个数表示答案
输入样例#1:
5 5 2 3 4 5 1 2 3 4 5 1 1 5 3 1 5 2 3 3 3 3 3 1 5 5
输出样例#1:
125 72 9 70
说明
对于30%的数据,n , m \le 1000n,m≤1000
对于另外20%的数据,所有储物点间的距离都为1
对于另外20%的数据,所有储物点的物品数都为1
对于100%的数据 ,n , m <= 200000 ; a_i , b_i <= 2* 10^9
题解:
我们先将公式写出,就会发现可以通过求前缀和实现O(1)询问。注意,要多取模。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long LL;
const LL mod = 19260817;
LL num[233333], val[233333];
LL sum1[233333], sum2[233333];
int main()
{
int n, m;
cin >> n >> m;
for (int i = 1; i < n; i++)
{
LL x;
scanf("%lld", &x);
num[i+1] = num[i] + x;
num[i+1] %= mod;
}
for (int i = 1; i <= n; i++)
scanf("%lld", &val[i]);
for (int i = 1; i <= n; i++)
sum1[i] = sum1[i-1]%mod + (val[i] * num[i]) % mod, sum1[i] %= mod, sum2[i] = sum2[i-1]%mod + val[i] % mod, sum2[i] %= mod;
for (int i = 1; i <= m; i++)
{
int x, l, r;
LL ans = 0;
scanf("%d%d%d", &x, &l, &r);
if (x < l)
ans = sum1[r]%mod - sum1[l-1]%mod - (((sum2[r] - sum2[l-1])%mod) * num[x])%mod;
else if (x > r)
ans = (((sum2[r] - sum2[l-1])%mod) * num[x])%mod - sum1[r]%mod + sum1[l-1]%mod;
else
{
ans = ((sum2[x] - sum2[l-1])%mod * num[x])%mod - sum1[x]%mod + sum1[l-1]%mod;
ans += (sum1[r] - sum1[x])%mod - (sum2[r] - sum2[x])%mod * num[x]%mod;
}
ans %= mod;
while (ans < 0)
ans += mod;
printf("%lld\n", ans);
}
return 0;
}