题目链接:P1975 [国家集训队]排队
题目大意: 给你一段数列,每次可以交换两个数的位置,问每次交换之后全局的逆序对个数。
题目分析: 对于一个序列,题目要求求动态的逆序对个数,考虑交换某两个位置,假设分别为
p
o
s
1
,
p
o
s
2
pos_1,pos_2
pos1,pos2,那么发生变化的逆序对一定是在
[
p
o
s
1
,
p
o
s
2
]
[pos_1,pos_2]
[pos1,pos2]这个区间上的,那么考虑交换,就等价于将
p
o
s
1
pos_1
pos1 位置的数字删去,将
p
o
s
2
pos_2
pos2 位置的数字删去,将
p
o
s
2
pos_2
pos2 位置加一个新数,将
p
o
s
1
pos_1
pos1位置加一个新数。因此考虑求区间排名,然后就可以离散化之后用树套树来解决了。
下面是代码 (写的丑轻喷)
题目代码:
#include<stdio.h>
#include<algorithm>
#include<string.h>
using namespace std;
#define mxn 100005
int Rt,n,m,Tot,tot,arr[mxn],brr[mxn],Ns[mxn],a[mxn],rt[mxn*10],sm[mxn*300],ls[mxn*300],rs[mxn*300],Ls[mxn*10],Rs[mxn*10];
void Add(int &k,int L,int R,int p,int o){
if(o==1&&!k)k=++tot;
if(k)sm[k]+=o;
if(!k||L==R)return;
int mid=(L+R)>>1;
if(p<=mid)Add(ls[k],L,mid,p,o);
else Add(rs[k],mid+1,R,p,o);
}
int Query(int k,int L,int R,int l,int r){
if(!k)return 0;
if(l<=L&&r>=R)return sm[k];
int mid=(L+R)>>1;
if(r<=mid)return Query(ls[k],L,mid,l,r);
else if(l>mid)return Query(rs[k],mid+1,R,l,r);
else return Query(ls[k],L,mid,l,mid)+Query(rs[k],mid+1,R,mid+1,r);
}
int Query_rank(int k,int L,int R,int l,int r,int f,int t){
if(!k)return 0;
if(l<=L&&r>=R)return Query(rt[k],1,n,f,t);
int mid=(L+R)>>1;
return (l<=mid?Query_rank(Ls[k],L,mid,l,r,f,t):0)+(r>mid?Query_rank(Rs[k],mid+1,R,l,r,f,t):0);
}
int Query_kth(int k,int L,int R,int x,int l,int r){
if(L==R)return L;
int mid=(L+R)>>1,tmp=Query(rt[Ls[k]],1,n,l,r);
if(x<=tmp)return Query_kth(Ls[k],L,mid,x,l,r);
else return Query_kth(Rs[k],mid+1,R,x-tmp,l,r);
}
void Update(int &k,int L,int R,int v,int p,int o){
if(o==1&&!k)k=++Tot;
if(k)Add(rt[k],1,n,p,o);
if(!k||L==R)return;
int mid=(L+R)>>1;
if(v<=mid)Update(Ls[k],L,mid,v,p,o);
else Update(Rs[k],mid+1,R,v,p,o);
}
int Get_pre(int x,int y,int z){
if(Query_rank(Rt,0,1e8,0,z-1,x,y)==Query_rank(Rt,0,1e8,0,-1e9,x,y))return -2147483647;
return Query_kth(Rt,0,1e8,Query_rank(Rt,0,1e8,0,z-1,x,y),x,y);
}
int Get_nxt(int x,int y,int z){
if(Query_rank(Rt,0,1e8,0,z,x,y)==Query_rank(Rt,0,1e8,0,1e9,x,y))return 2147483647;
return Query_kth(Rt,0,1e8,Query_rank(Rt,0,1e8,0,z,x,y)+1,x,y);
}
int ans;
void mergesort(int l,int mid,int r)
{
int ll=l,rr=mid+1,ss=l;
while(ss<=r){
if(rr>r||arr[ll]<=arr[rr]&&ll<=mid) {
brr[ss]=arr[ll];
ll++;
}
else{
brr[ss]=arr[rr];
ans+=mid-ll+1;
rr++;
}
ss++;
}
for(int i=l;i<=r;++i)
arr[i]=brr[i];
}
void merge(int l,int r)
{
if(l==r)return ;
int mid=(l+r)/2;
merge(l,mid);
merge(mid+1,r);
mergesort(l,mid,r);
}
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%d",&arr[i]);
Ns[i]=arr[i];
}
sort(Ns+1,Ns+n+1);
int N=unique(Ns+1,Ns+n+1)-Ns-1;
for(int i=1;i<=n;i++)
arr[i]=a[i]=lower_bound(Ns+1,Ns+N+1,arr[i])-Ns;
for(int i=1;i<=n;i++)
Update(Rt,0,1e9,arr[i],i,1);
merge(1,n);
for(int i=1;i<=n;i++)
arr[i]=a[i];
printf("%d\n",ans);
scanf("%d",&m);
for(int i=1;i<=m;i++){
int a,b;
scanf("%d %d",&a,&b);
if(a>b)swap(a,b);
if(arr[a]>arr[b])--ans;
if(arr[a]<arr[b])++ans;
if(b!=a+1){
int len=b-a-1;
int ns=Query_rank(Rt,0,1e9,0,arr[a]-1,a+1,b-1);//<a
int np=Query_rank(Rt,0,1e9,0,arr[b]-1,a+1,b-1);//<b
int nt=len-Query_rank(Rt,0,1e9,0,arr[a],a+1,b-1);//>a
int nq=len-Query_rank(Rt,0,1e9,0,arr[b],a+1,b-1);//>b
ans=ans-ns+np-nq+nt;
}swap(arr[a],arr[b]);
Update(Rt,0,1e9,arr[b],a,-1);
Update(Rt,0,1e9,arr[b],b,1);
Update(Rt,0,1e9,arr[a],b,-1);
Update(Rt,0,1e9,arr[a],a,1);
printf("%d\n",ans);
}
return 0;
}