题意:给一个序列,若干个询问,每次询问一个区间的逆序对个数。
考虑数据范围很小,就可以使用莫队,如何计算扩展的一个点的贡献?用树状数组维护即可。
c
o
d
e
:
code:
code:
#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;
}
/*
考虑树状数组怎么维护
左端点往前:
会增加一些数,考虑这些数产生的贡献,那就是后面比它小的数的个数,显然可以做到
左端点往后:
会减少一些数,考虑这些数产生的影响,还是后面比它小的数的个数。
右端点往后:
多了几个数, 这些数产生的贡献便是前面比它大的数的个数。
右端点往前:
那就是答案减去前面比他大的数的个数。
*/