题意:给定i和i+1两点的距离,i点的货物数量,以及费用计算方法ans=x * dist( i , j ),dist(i,j)为两点间距离
然后每次查询将区间(i,j)的货物全部转移到x点所需要的费用ans
题解:前缀和
(1)求1点到i点的距离前缀和a[]
区间[1,i]点货物集中到1点,1点货物总和的前缀和b[]
区间[1,i]点货物集中到1点,所需要的价值的前缀和c[]
(2)分情况讨论
区间[L,R],点X
如果X小于等于L,那么可以先把区间[L,R]所有的货物集中到1点的花费为c[R]-c[L],但是对于对于每个j点,j在[L,R],都多走了a[x],所以要减去(b[R]-b[L])*a[x]
如果X大于等于R,那么可以先让b[R]-b[L]数量的货物从a[1]走到a[x],但是对于每个j点,j在[L,R]之间都多走了a[j],算下来总共多走了c[R]-c[L]
如果X在L和R之间,那么按照上述式子先求解,把L当作R情况,即求解[L,X]
然后求[X,R]相当于上面两种情况结合
时间复杂度:O(n)
#include<bits/stdc++.h> #define int long long using namespace std; const int N=2e5+10,p=1e9+7; int n,m,a[N],w[N],s[N]; signed main(){ ios::sync_with_stdio(false); cin.tie(nullptr); cout.tie(nullptr); cin>>n>>m; for(int i=2;i<=n;i++) cin>>a[i],a[i]=(a[i]+a[i-1])%p; for(int i=1;i<=n;i++){ cin>>w[i]; s[i]=(a[i]*w[i]%p+s[i-1]+s[i])%p; w[i]=(w[i]+w[i-1])%p; } while(m--){ static int x,l,r,res; cin>>x>>l>>r; if(x<=l){ res=(s[r]-s[l-1]+p)%p; res=(res-(w[r]-w[l-1]+p)%p*a[x]%p+p)%p; }else if(x>=r){ res=((w[r]-w[l-1]+p)%p*a[x]%p-(s[r]-s[l-1]+p)%p+p)%p; }else{ res=(s[r]-s[x-1]+p)%p; res=(res-(w[r]-w[x-1]+p)%p*a[x]%p+p)%p; res=(res+(w[x]-w[l-1]+p)%p*a[x]%p-(s[x]-s[l-1]+p)%p)%p; } res=(res+p)%p; cout<<res<<'\n'; } return 0; }