题意:
给出一段长为n的数列,求其逆序对数;
然后给出m个操作,每次操作给出l,r;
交换l,r并输出操作之后的逆序对数;
n<=2x10^4,m<=2x10^3;
题解:
求逆序对本来是一个很简单的事情,然而动态修改就不能用树状数组直接搞了;
因为树状数组求逆序对是不支持区分某个数在它前面还是后面的;
所以考虑求在它之前小于它的数的个数,用线段树维护区间,套treap维护排名;
在求排名的过程中顺便记录一个cnt表示区间中与这个数相等的点;
然后对于每次修改,逆序对数ans的更改:
a[ l ]移到后面就是ans减去比它小的个数,加上比它大的个数;
比它大的就是区间长减去cnt减去比它小的咯;
a[ r ]同理,之后再维护树套树就可以了;
HINT:
l可能大于r;
小心重复计算区间端点的逆序对;
代码:
#include<stdio.h>
#include<string.h>
#include<algorithm>
#define N 20001
#define M 2000000
#define lson l,mid,no<<1
#define rson mid+1,r,no<<1|1
using namespace std;
struct node
{
int val,rnd,l,r,w,size;
}treap[M];
int n,m,tot,ans,cnt;
int root[N<<2],a[N];
void Pushup(int no)
{
treap[no].size=treap[treap[no].l].size+treap[treap[no].r].size+treap[no].w;
}
void lturn(int &no)
{
int temp=treap[no].r;
treap[no].r=treap[temp].l;
treap[temp].l=no;
treap[temp].size=treap[no].size;
Pushup(no);
no=temp;
}
void rturn(int &no)
{
int temp=treap[no].l;
treap[no].l=treap[temp].r;
treap[temp].r=no;
treap[temp].size=treap[no].size;
Pushup(no);
no=temp;
}
void insert(int &no,int val)
{
if(!no)
{
no=++tot;
treap[no].size=treap[no].w=1;
treap[no].val=val,treap[no].rnd=rand();
return ;
}
treap[no].size++;
if(val==treap[no].val)
treap[no].w++;
else if(val<treap[no].val)
{
insert(treap[no].l,val);
if(treap[treap[no].l].rnd<treap[no].rnd)
rturn(no);
}
else
{
insert(treap[no].r,val);
if(treap[treap[no].r].rnd<treap[no].rnd)
lturn(no);
}
}
void del(int &no,int val)
{
if(val==treap[no].val)
{
if(treap[no].w>1)
treap[no].w--,treap[no].size--;
else if(treap[no].l*treap[no].r==0)
no=treap[no].l+treap[no].r;
else if(treap[treap[no].l].rnd<treap[treap[no].r].rnd)
rturn(no),del(no,val);
else
lturn(no),del(no,val);
return ;
}
treap[no].size--;
if(val<treap[no].val)
del(treap[no].l,val);
else
del(treap[no].r,val);
}
void build(int l,int r,int no,int k,int val)
{
insert(root[no],val);
if(l==r) return ;
int mid=(l+r)>>1;
if(k<=mid) build(lson,k,val);
else build(rson,k,val);
}
void update(int l,int r,int no,int k,int val,int pre)
{
del(root[no],pre);
insert(root[no],val);
if(l==r) return ;
int mid=(l+r)>>1;
if(k<=mid) update(lson,k,val,pre);
else update(rson,k,val,pre);
}
int ask_rank(int no,int val)
{
if(!no) return 0;
if(val==treap[no].val)
{
cnt+=treap[no].w;
return treap[treap[no].l].size;
}
else if(val<treap[no].val)
return ask_rank(treap[no].l,val);
else
return treap[treap[no].l].size+treap[no].w+ask_rank(treap[no].r,val);
}
int get_rank(int l,int r,int no,int st,int en,int val)
{
if(st<=l&&r<=en)
return ask_rank(root[no],val);
int mid=(l+r)>>1;
if(en<=mid) return get_rank(lson,st,en,val);
else if(st>mid) return get_rank(rson,st,en,val);
else return get_rank(lson,st,en,val)+get_rank(rson,st,en,val);
}
int main()
{
int i,j,k,l,r;
scanf("%d",&n);
for(i=1;i<=n;i++)
{
scanf("%d",a+i);
build(1,n,1,i,a[i]);
cnt=0;
ans+=i-get_rank(1,n,1,1,i,a[i]);
ans-=cnt;
}
printf("%d\n",ans);
scanf("%d",&m);
for(i=1;i<=m;i++)
{
scanf("%d%d",&l,&r);
if(l==r||a[l]==a[r])
{
printf("%d\n",ans);
continue;
}
if(l>r) swap(l,r);
cnt=0;
ans-=get_rank(1,n,1,l,r,a[l])<<1;
ans+=r-l+1-cnt;
cnt=0;
ans+=get_rank(1,n,1,l+1,r,a[r])<<1;
ans-=r-l-cnt;
update(1,n,1,l,a[r],a[l]);
update(1,n,1,r,a[l],a[r]);
swap(a[l],a[r]);
printf("%d\n",ans);
}
return 0;
}