考虑莫队。
如果是单纯的莫队的话,还需要一个树状数组来维护逆序对数,这样子的话复杂度是 (O(n^{1.5}log n)),难以接受。
怎么将这个树状数组消除?
考虑当前区间为 ([l,r-1]) ,需要将右端点向右移动,即加入 (a_r) ,并且将答案加上 (a_{l,l+1,cdots,r-1}) 中大于 (a_r) 的数的个数。其实这也就等于 (a_{1cdots r-1}) 中大于 (a_r) 的个数减去 (a_{1cdots l-1}) 中大于 (a_r) 的个数。
第一个贡献可以直接将整个数组扫一遍处理,时间复杂度 (O(nlog n)) 。
第二个询问的话,考虑将 (l-1) 处开个桶,然后将 (r) 丢入。因为莫队的移动次数是 (O(nsqrt{m})) 的,因此空间的需求量也是 (O(nsqrt{m})) 的。
最后只需要枚举左端点,然后获取其桶中的数的答案即可。
但是这题卡空间,不能直接存储贡献。同时可以发现一个 (l) 对应的一段 (r) 其实是连续的,因此直接将区间做右端点存下即可。
注意 ans
记录的是答案变化量,因此最终还需要做一遍前缀和。
(其实就是相当于将莫队的转移再次离线
// #define debug
const int N=1e5+5;
int n,m,_,a[N];
ll ans[N];
struct Query {int l,r,id;} q[N];
// {{{ unique_a
inline void unique_a() {
static int h[N];
lep(i,1,n) h[i]=a[i];
std::sort(h+1,h+1+n),_=1;
lep(i,2,n) if(h[_]!=h[i]) h[++_]=h[i];
lep(i,1,n) a[i]=std::lower_bound(h+1,h+1+_,a[i])-h;
}
// }}}
namespace Get_Pre { // {{{
ll pre[N],suf[N];
// {{{ BIT
int res,c[N];
inline int lowbit(int x) {return x&(-x);}
inline void modify(int x) {for(;x<=_;x+=lowbit(x)) ++c[x];}
inline int query(int x) {res=0; for(;x;x-=lowbit(x)) res+=c[x]; return res;}
inline void clear() {CLEAR(c);}
// }}}
inline void solve() {
clear(); lep(i,1,n) pre[i]=pre[i-1]+query(_-a[i]),modify(_-a[i]+1);
clear(); rep(i,n,1) suf[i]=suf[i+1]+query(a[i]-1),modify(a[i]);
}
} using Get_Pre::pre,Get_Pre::suf; // }}}
// {{{ Solve
struct Node {int l,r,id,typ;};
std::vector <Node> sta1[N],sta2[N];
// {{{ Block
const int SqrtN=4e2+5;
int id[N],val[N],L[SqrtN],R[SqrtN],sum[SqrtN];
inline int query(int x) {return val[x]+sum[id[x]];}
inline void update1(int x) {
lep(i,L[id[x]],x-1) ++val[i];
lep(i,1,id[x]-1) ++sum[i];
}
inline void update2(int x) {
lep(i,x+1,R[id[x]]) ++val[i];
lep(i,id[x]+1,id[_]) ++sum[i];
}
inline void clear() {CLEAR(val),CLEAR(sum);}
// }}}
inline void solve() {
int B=sqrt(_);
for(int l=1,r=0,c=1;l<=_;l=r+1,++c) {
r=min(l+B-1,_),L[c]=l,R[c]=r;
lep(i,l,r) id[i]=c;
}
clear(); lep(i,1,n) {
update1(a[i]);
for(Node now:sta1[i]) lep(j,now.l,now.r) ans[now.id]+=1ll*query(a[j])*now.typ;
}
clear(); rep(i,n,1) {
update2(a[i]);
for(Node now:sta2[i]) lep(j,now.l,now.r) ans[now.id]+=1ll*query(a[j])*now.typ;
}
}
// }}}
int pos[N];
int main() {
IN(n,m);
lep(i,1,n) IN(a[i]);
lep(i,1,m) IN(q[i].l,q[i].r),q[i].id=i;
unique_a();
Get_Pre::solve();
#ifdef debug
printf("a : "); lep(i,1,n) printf("%d ",a[i]); puts("");
printf("pre : "); lep(i,1,n) printf("%lld ",pre[i]); puts("");
printf("suf : "); lep(i,1,n) printf("%lld ",suf[i]); puts("");
#endif
int B=n/sqrt(m*2/3+1);
std::sort(q+1,q+1+m,[&](Query x,Query y){return (x.l/B)^(y.l/B)?x.l<y.l:x.r<y.r;});
lep(i,1,m) pos[q[i].id]=i;
int l=1,r=0;
lep(i,1,m) {
if(r<q[i].r) ans[i]+=(pre[q[i].r]-pre[r]),sta1[l-1].pb((Node){r+1,q[i].r,i,-1}),r=q[i].r;
if(r>q[i].r) ans[i]-=(pre[r]-pre[q[i].r]),sta1[l-1].pb((Node){q[i].r+1,r,i,1}),r=q[i].r;
if(l<q[i].l) ans[i]-=(suf[l]-suf[q[i].l]),sta2[r+1].pb((Node){l,q[i].l-1,i,1}),l=q[i].l;
if(l>q[i].l) ans[i]+=(suf[q[i].l]-suf[l]),sta2[r+1].pb((Node){q[i].l,l-1,i,-1}),l=q[i].l;
}
solve();
lep(i,1,m) ans[i]+=ans[i-1];
lep(i,1,m) printf("%lld
",ans[pos[i]]);
return 0;
}