题意
小明有一个含有n个数的数列 a1,a2,…,an 。
他定义一个数列的积为
∑ni=1∑nj=i|ai−aj∗(j−i)
他发现算出数列积实际上非常简单。因此他现在有了一个绝妙的主意。
他有Q个询问。
对于每个询问会给定两个参数 l,r 。
他想知道的是,将 al,al+1,…,ar 拿出来成为一个数列,问该数列的数列积是多少。
由于答案很大,他表示只要求出数列积对 264 取模后的值就可以了。
1<=n<=50000,1<=ai<=100000,1<=Q<=50000
分析
题解是十分鬼畜的分块做法。明明在询问的时候有排序还说自己的复杂度是 O(nn√) 。。。
可以上莫队,直接把式子展开用树状数组维护四项即可。
卡常卡了好久,最后把树状数组的传参减少了,就跑的快了很多。这告诉我们不要传太多参数。
代码
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
typedef unsigned long long LL;
const int N=50005;
int n,m,bel[N],a[N],mx,stack[25];
LL c1[N*2],c2[N*2],c3[N*2],c4[N*2],val,ans[N],s1,s2,s3,s4,y;
struct data{int l,r,id;}q[N];
inline int read()
{
int x=0,f=1;char ch=getchar();
while (ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while (ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
inline void pri(LL x)
{
if (!x) {puts("0");return;}
int top=0;
while (x) stack[++top]=x%10,x/=10;
while (top) putchar(stack[top]+'0'),top--;
puts("");
}
bool cmp(data a,data b)
{
return bel[a.l]<bel[b.l]||bel[a.l]==bel[b.l]&&a.r<b.r;
}
inline void ins(int x,LL y)
{
LL w1=x*y,w2=a[x]*y,w3=w1*w2*y;x=a[x];
while (x<=mx) c1[x]+=y,c2[x]+=w1,c3[x]+=w2,c4[x]+=w3,x+=x&(-x);
}
inline void find(int x)
{
LL w1=0,w2=0,w3=0,w4=0;
while (x) w1+=c1[x],w2+=c2[x],w3+=c3[x],w4+=c4[x],x-=x&(-x);
s1+=w1*y;s2+=w2*y;s3+=w3*y;s4+=w4*y;
}
inline void updata(int x,int op,LL f)
{
ins(x,f);
if (op==0)
{
s1=s2=s3=s4=0;
y=1;find(a[x]-1);
val+=f*((LL)a[x]*s2-(LL)x*a[x]*s1-(LL)s4+(LL)x*s3);
s1=s2=s3=s4=0;
y=1;find(mx);y=-1;find(a[x]);
val+=f*(s4-(LL)x*s3-(LL)a[x]*s2+(LL)x*a[x]*s1);
}
else
{
s1=s2=s3=s4=0;
y=1;find(a[x]-1);
val+=f*((LL)x*a[x]*s1-(LL)a[x]*s2-(LL)x*s3+(LL)s4);
s1=s2=s3=s4=0;
y=1;find(mx);y=-1;find(a[x]);
val+=f*((LL)x*s3-s4-(LL)x*a[x]*s1+(LL)a[x]*s2);
}
}
void solve()
{
for (int i=1,l=1,r=0;i<=m;i++)
{
for (;r<q[i].r;r++) updata(r+1,1,1);
for (;l>q[i].l;l--) updata(l-1,0,1);
for (;r>q[i].r;r--) updata(r,1,-1);
for (;l<q[i].l;l++) updata(l,0,-1);
ans[q[i].id]=val;
}
}
int main()
{
n=read();int block=sqrt(n);
for (int i=1;i<=n;i++) a[i]=read(),bel[i]=(i+block-1)/block,mx=max(mx,a[i]);
m=read();
for (int i=1;i<=m;i++) q[i].l=read(),q[i].r=read(),q[i].id=i;
sort(q+1,q+m+1,cmp);
solve();
for (int i=1;i<=m;i++) pri(ans[i]);
return 0;
}