題意:給一個序列,若干個詢問,每次詢問一個區間的逆序對個數。
考慮數據範圍很小,就可以使用莫隊,如何計算擴展的一個點的貢獻?用樹狀數組維護即可。
#include <bits/stdc++.h>
#define int long long
#define regi register int
int n,q;
int a[51000];
int tmp[51000],cnt;
int pos[51000];
int ans[51000];
int s=0;
int c[51000];
int L,R;
std::map<int,int>Dis;
struct question{
int l;
int r;
int id;
}ques[51000];
inline bool compare_for_l(question x,question y){
if(pos[x.l]==pos[y.l]){
return x.r<y.r;
}
return pos[x.l]<pos[y.l];
}
inline void add(int x,int v){
for(;x<=n;x+=x&-x)
c[x]+=v;
}
inline int ask(int x){
int S=0;
for(;x;x-=x&-x)
S+=c[x];
return S;
}
main(){
scanf("%lld",&n);
for(regi i=1,blk=sqrt(n);i<=n;++i){
scanf("%lld",&a[i]);
tmp[i]=a[i];
pos[i]=(i-1)/blk+1;
}
std::sort(tmp+1,tmp+n+1);
for(regi i=1;i<=n;++i)
if(tmp[i]!=tmp[i-1])
Dis[tmp[i]]=++cnt;
for(regi i=1;i<=n;++i)
a[i]=Dis[a[i]];
scanf("%lld",&q);
for(regi i=1;i<=q;++i){
scanf("%lld%lld",&ques[i].l,&ques[i].r);
ques[i].id=i;
}
std::sort(ques+1,ques+q+1,compare_for_l);
L=1;
for(regi i=1;i<=q;++i){
while(L<ques[i].l){
s-=ask(a[L]-1);
add(a[L],-1);
++L;
}
while(R>ques[i].r){
add(a[R],-1);
s-=R-L-ask(a[R]);
--R;
}
while(L>ques[i].l){
--L;
s+=ask(a[L]-1);
add(a[L],1);
}
while(R<ques[i].r){
++R;
s+=R-L-ask(a[R]);
add(a[R],1);
}
ans[ques[i].id]=s;
}
for(regi i=1;i<=q;++i)
printf("%lld\n",ans[i]);
return 0;
}
/*
考慮樹狀數組怎麼維護
左端點往前:
會增加一些數,考慮這些數產生的貢獻,那就是後面比它小的數的個數,顯然可以做到
左端點往後:
會減少一些數,考慮這些數產生的影響,還是後面比它小的數的個數。
右端點往後:
多了幾個數, 這些數產生的貢獻便是前面比它大的數的個數。
右端點往前:
那就是答案減去前面比他大的數的個數。
*/