1. 程式人生 > >洛谷P3932 浮游大陸的68號島

洛谷P3932 浮游大陸的68號島

題目描述

有一天小妖精們又在做遊戲。這個遊戲是這樣的。

妖精倉庫的儲物點可以看做在一個數軸上。每一個儲物點會有一些東西,同時他們之間存在距離。

每次他們會選出一個小妖精,然後剩下的人找到區間[l,r]儲物點的所有東西,清點完畢之後問她,把這個區間內所有儲物點的東西運到另外一個倉庫的代價是多少?

比如儲物點i有x個東西,要運到儲物點j,代價為

x×dist(i,j)x \times \mathrm{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,m200000;ai,bi<=2109n , m \le 200000 ; a_i , b_i <= 2\cdot 10^9

題目分析

參考了luogu題解某dalao sumD[i]sumD[i]記錄從i

i11的距離 sumA[i]sumA[i]是物品數量a[i]a[i]的字首和 sumDA[i]sumDA[i]記錄sumD[i]a[i]sumD[i]*a[i]的字首和

對於每次詢問區間我們拆成兩個小區間[ll,x1],[x+1,rr][ll,x-1],[x+1,rr] 以左邊這個為例,其運輸總費用為 i=llx1(sumD[x]sumD[i])a[i]\sum_{i=ll}^{x-1}(sumD[x]-sumD[i])*a[i]

a[i] i=llx1sumD[x]a[i]sumD[i]a[i]\sum_{i=ll}^{x-1}sumD[x]*a[i]-sumD[i]*a[i] sumD[x]i=llx1a[i]i=llx1sumD[i]a[i]sumD[x]\sum_{i=ll}^{x-1}a[i]-\sum_{i=ll}^{x-1}sumD[i]*a[i] sumD[x](sumA[x1]sumA[ll1])(sumDA[x1]sumDA[ll1])sumD[x]*(sumA[x-1]-sumA[ll-1])-(sumDA[x-1]-sumDA[ll-1])

對於右邊的區間用同樣的方法推導發現就是對上面這個答案取個反 (sumDA[x1]sumDA[ll1])sumD[x](sumA[x1]sumA[ll1])(sumDA[x-1]-sumDA[ll-1])-sumD[x]*(sumA[x-1]-sumA[ll-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;
}