题目链接:###
分析:###
设每个点到1号点的距离为dist_{i},每个点的权值为x_{i},目标点到1号点的距离为dist,权值为x,那么对于每一次查询,我们讨论三种情况:
① 目标家庭在区间左边(x<=l)
如图所示
这种情况下
ans=sum((dist_{i}-dist)*x_{i])
=sum(dist_{i]*x_{i}) - dist*sum(x_{i})
②目标家庭在区间右边(x>=r)
容易同理得到
ans= dist*sum(x_{i})-sum(dist_{i]*x_{i})
③目标家庭在区间中间(l<x<r)
将区间从目标家庭处分开,分别求左右子区间的ans1,ans2,过程同①,②
为了降低时间复杂度,每个点到1号点的距离,每个点的权值,以及前两项的乘积都用前缀和来存储,于是我们维护三个前缀和数组——代码中分别是dist,b,p,这样对于每次查询的时间复杂度是O(1)的,总时间复杂度为O(N)。
被坑到的点:
相减的时候可能出现负值,对应的余数也会变成负值,这时候加一个特判
if(ans<0)ans+=mod;
即可。(不加会见祖宗你信吗)
代码如下:
#include<bits/stdc++.h>
#define frog 19260817
using namespace std;
inline long long read(){
int cnt=0,f=1;char c;
c=getchar();
while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}
while(isdigit(c)){cnt=cnt*10+c-'0';c=getchar();}
return cnt*f;
}
long long n,m,dist[200005],x=0,a,l,r;
long long p[200005],b[200005];
long long ans;
int main(){
n=read();m=read();
memset(dist,0,sizeof(dist));
memset(p,0,sizeof(p));
memset(b,0,sizeof(b));
for(register int i=2;i<=n;i++){
x=read();
dist[i]=(x+dist[i-1])%frog;
}
for(register int i=1;i<=n;i++){
x=read();
b[i]=(x+b[i-1])%frog;
p[i]=(p[i-1]+x*dist[i])%frog;
}
for(register int i=1;i<=m;i++){
a=read();l=read();r=read();
if(a<=l){
long long t1=(p[r]-p[l-1])%frog;
long long t2=((b[r]-b[l-1])*dist[a])%frog;
ans=(t1-t2)%frog;
}
if(a>=r){
long long t1=(p[r]-p[l-1])%frog;
long long t2=((b[r]-b[l-1])*dist[a])%frog;
ans=(t2-t1)%frog;
}
if(l<a&&a<r){
long long t1=(p[a]-p[l-1])%frog;
long long t2=((b[a]-b[l-1])*dist[a])%frog;
long long t3=(p[r]-p[a])%frog;
long long t4=((b[r]-b[a])*dist[a])%frog;
ans=((t2-t1+t3-t4)%frog)%frog;
}
if(ans<0)ans+=frog;
printf("%lld\n",ans);
}
return 0;
}