真tm线段树神题。。。
设 [l,r] 复杂值为 Tl,r
首先对于询问 [l,r] ,把问题转化为: ∑ni=1∑nj=iTi,j−∑l−1i=1∑l−1j=iTi,j−∑ni=r+1∑nj=iTi,j
我们先考虑前缀的,后缀的反过来再做一遍就是了。
我们设 fi 为 ∑ij=1Tj,i ,那么 fi 的前缀和就是所求。
从左到右扫,考虑用一棵权值线段树维护每个权值的贡献,扫到 i 时,把 ≥ai 的权值的贡献全部乘上 k ,再加上 ai 对 fi 贡献即可。
ai 对 fi 贡献如何计算呢?考虑预处理每个 ai 对 fi 的贡献,也就是 ∑ij=1knumj,i , numj,i 表示 [j,i] 中比 ai 小的数的个数。开一棵线段树,按 ai 从小到大插入,位置 x 表示上式中为 j=x 的贡献,每次插入就是把 [1,i] 乘上 k ,然后查询 ai 贡献是在插入之前,就是 [1,i−1] 的和,因为这个时候对于 i 位置的乘 k 操作都是多余的,所以记录下多乘的 k ,最后乘上逆元即可。
然后 fi 就求出来了,前缀和一下,再反着做一遍,对于每个询问就 O(1) 了。
代码:
#include
#include
#include
#include
#define ll long long
#define N 300010
#define mid (l+r>>1)
#define pii pair
#define fs first
#define sc second
using namespace std;
const int mod=1000000007;
int n,m,K,a[N],z[N];
pii r[N];
ll mi[N],f[2][N],s[2][N],inv[N];
int read()
{
char ch=getchar();int x=0;
for(;ch<'0'||ch>'9';ch=getchar());
for(;ch>='0'&&ch<='9';ch=getchar()) x=x*10+ch-'0';
return x;
}
ll ksm(ll a,int b){ll r=1;for(;b;b>>=1){if(b&1)r=r*a%mod;a=a*a%mod;}return r;}
struct tree
{
ll sum,div;
int mul;
tree *ls,*rs;
tree(){ls=rs=NULL;}
void update()
{
sum=ls->sum+rs->sum;
}
void cal(int d)
{
(sum*=mi[d])%=mod;
(div*=inv[d])%=mod;
}
void pushdown()
{
if(mul)
{
ls->cal(mul);
rs->cal(mul);
ls->mul+=mul;
rs->mul+=mul;
mul=0;
}
}
void build(int l,int r,int f)
{
sum=f;mul=0;div=1;
if(l==r) return;
if(!ls) ls=new tree;
if(!rs) rs=new tree;
ls->build(l,mid,f);
rs->build(mid+1,r,f);
update();
}
void add(int pl,ll d,int l,int r)
{
if(l==r) {(sum+=d)%=mod;return ;}
pushdown();
if(pl<=mid) ls->add(pl,d,l,mid);
else rs->add(pl,d,mid+1,r);
update();
}
void mdf(int lx,int rx,int d,int l,int r)
{
if(l==lx&&r==rx) {mul+=d;cal(d);return ;}
pushdown();
if(rx<=mid) ls->mdf(lx,rx,d,l,mid);
else if(lx>mid) rs->mdf(lx,rx,d,mid+1,r);
else ls->mdf(lx,mid,d,l,mid),rs->mdf(mid+1,rx,d,mid+1,r);
update();
}
ll qry(int lx,int rx,int l,int r)
{
if(l==lx&&r==rx) return sum;
pushdown();
if(rx<=mid) return ls->qry(lx,rx,l,mid);
else if(lx>mid) return rs->qry(lx,rx,mid+1,r);
else return (ls->qry(lx,mid,l,mid)+rs->qry(mid+1,rx,mid+1,r))%mod;
}
ll getinv(int pl,int l,int r)
{
if(l==r) return div;
pushdown();
if(pl<=mid) return ls->getinv(pl,l,mid);
else return rs->getinv(pl,mid+1,r);
}
}*xtr;
void work(int b)
{
xtr->build(1,n,K);
for(int i=1;i<=n;i++)
{
ll t1=xtr->qry(1,r[i].sc,1,n),t2=xtr->getinv(r[i].sc,1,n);
s[b][r[i].sc]=t1*t2%mod;
xtr->mdf(1,r[i].sc,1,1,n);
}
xtr->build(1,n,0);
for(int i=1;i<=n;i++)
{
xtr->add(a[i],s[b][i]*z[a[i]]%mod,1,n);
if(a[i]mdf(a[i]+1,n,1,1,n);
f[b][i]=xtr->sum;
}
for(int i=1;i<=n;i++)
(f[b][i]+=f[b][i-1])%=mod;
if(b)
for(int i=1;i<=(n>>1);i++)
swap(f[b][i],f[b][n-i+1]);
}
int main()
{
n=read();m=read();K=read();
for(int i=1;i<=n;i++)
z[i]=a[i]=read(),r[i]=make_pair(a[i],i);
sort(z+1,z+n+1);
sort(r+1,r+n+1);
for(int i=1;i<=n;i++)
a[i]=lower_bound(z+1,z+n+1,a[i])-z;
mi[0]=1;
for(int i=1;i<=n;i++)
mi[i]=mi[i-1]*K%mod;
inv[n]=ksm(mi[n],mod-2);
for(int i=n-1;i>=0;i--)
inv[i]=inv[i+1]*K%mod;
xtr=new tree;
work(0);
for(int i=1;i<=(n>>1);i++)
swap(a[i],a[n-i+1]);
for(int i=1;i<=n;i++)
r[i].sc=n-r[i].sc+1;
work(1);
while(m--)
{
int l=read(),r=read();
printf("%lld\n",(f[0][n]-f[0][l-1]-f[1][r+1]+mod*2)%mod);
}
return 0;
}