洛谷P3932 浮游大陆的68号岛

有一天小妖精们又在做游戏。这个游戏是这样的。

妖精仓库的储物点可以看做在一个数轴上。每一个储物点会有一些东西,同时他们之间存在距离。

每次他们会选出一个小妖精,然后剩下的人找到区间[l,r][l,r][l,r]储物点的所有东西,清点完毕之后问她,把这个区间内所有储物点的东西运到另外一个仓库的代价是多少?

比如储物点iiixxx个东西,要运到储物点jjj,代价为

x×dist(i,j)x \times \mathrm{dist}( i , j )x×dist(i,j)

dist就是仓库间的距离。

当然啦,由于小妖精们不会算很大的数字,因此您的答案需要对19260817取模。

输入输出格式

输入格式:

第一行两个数表示n,mn,mn,m

第二行n−1n-1n1个数,第iii个数表示第iii个储物点与第i+1i+1i+1个储物点的距离

第三行nnn个数,表示每个储物点的东西个数

之后mmm行每行三个数x l r

表示查询要把区间[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
0
70

说明

对于30%的数据,n,m≤1000n , m \le 1000n,m1000

对于另外20%的数据,所有储物点间的距离都为1

对于另外20%的数据,所有储物点的物品数都为1

对于100%的数据 ,n,m≤200000;ai,bi<=2⋅109 n , m \le 200000 ; a_i , b_i <= 2\cdot 10^9n,m200000;ai,bi<=2109

首先我们设viv_ivi表示第i个位置上的物品数量,维护一个前缀和disidis_idisi表示第i个位置到第一个位置的距离

由此我们可以得出以下公式:ans=∑i=1nvi∣disi−disx∣ans=\sum_{i=1}^{n}v_i|dis_i-dis_x|ans=i=1nvidisidisx化简得:ans=∑i=1n∣vidisi−vidisx∣ans=\sum_{i=1}^{n}|v_i dis_i-v_i dis_x|ans=i=1nvidisividisx我们发现:对于每一个i,它的vidisiv_i dis_ividisi是一个定值,那么我们就也用一个前缀和mulimul_imuli来维护第i个位置上的物品数量与disidis_idisi的乘积

最后在维护一个前缀和sumisum_isumi储存前i个位置中物品的总量

当我们求最终答案的时候需要考虑三种情况:

1 对于输入的x、l、r满足x≤lx \leq lxl

这种情况的答案ans=(mulr−mull−1)−(sumr−suml−1)disians=(mul_{r}-mul_{l-1})-(sum_{r}-sum_{l-1})dis_ians=(mulrmull1)(sumrsuml1)disi

2 对于输入的x、l、r满足r≤xr \leq xrx

很显然这种情况的ans=sumr−suml−1)disi−(mulr−mull−1)ans=sum_{r}-sum_{l-1})dis_i-(mul_{r}-mul_{l-1})ans=sumrsuml1)disi(mulrmull1)

3 需要注意的就是l≤x≤rl \leq x \leq rlxr的这种情况

对于区间内x之前的部分,有ans=(sumx−1−suml−1)disx−(mulx−1−mull−1)ans=(sum_{x-1}-sum_{l-1})dis_x-(mul_{x-1}-mul_{l-1})ans=(sumx1suml1)disx(mulx1mull1)

对于区间内x之后的部分,有ans=(mulr−mulx)−(sumr−sumx)disxans=(mul_{r}-mul_{x})-(sum_{r}-sum_{x})dis_{x}ans=(mulrmulx)(sumrsumx)disx

然后我们把两个ans加起来就是这种情况的答案

#include<iostream>
#define f(i,l,r) for(i=(l);i<=(r);i++)
using namespace std;
const int MAXN=200005,MOD=19260817;
long long n,m,dis[MAXN],w[MAXN];
long long c1[MAXN],c2[MAXN];
long long Plus(long long a,long long b)
{
	a=(a+MOD)%MOD;b=(b+MOD)%MOD;
	return (a+b)%MOD;
}
long long minu(long long a,long long b)
{
	a=(a+MOD)%MOD;b=(b+MOD)%MOD;
	return (a-b+MOD)%MOD;
}
long long mult(long long a,long long b)
{
	a=(a+MOD)%MOD;b=(b+MOD)%MOD;
	return (a*b)%MOD;
}
int main()
{
	ios::sync_with_stdio(false);
	int i,j,x,l,r;
	long long ans;
	cin>>n>>m;
	f(i,2,n){
		cin>>dis[i];
		dis[i]=Plus(dis[i],dis[i-1]);
	}
	f(i,1,n){
		cin>>w[i];
		c1[i]=Plus(mult(w[i],dis[i]),c1[i-1]);
		c2[i]=Plus(c2[i-1],w[i]);
	}
	f(i,1,m){
		cin>>x>>l>>r;
		if(x<=l){
			ans=minu(minu(c1[r],c1[l-1]),mult(dis[x],minu(c2[r],c2[l-1])));
		}
		else if(x>=r){
			ans=minu(mult(dis[x],minu(c2[r],c2[l-1])),minu(c1[r],c1[l-1]));
		}
		else{
			ans=minu(mult(dis[x],minu(c2[x],c2[l-1])),minu(c1[x],c1[l-1]));
			ans=Plus(ans,minu(minu(c1[r],c1[x-1]),mult(dis[x],minu(c2[r],c2[x-1]))));
		}
		cout<<(ans+MOD)%MOD<<endl;
	}
	return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值