方法:树套树(线段树+平衡树)(貌似树状数组+平衡树也可搞?)
题解:
首先这道题的题意是求区间逆序对,题中好像没说清?
主要的解题思路就是第一次先把所有的点加进树套树,之后对于每一个值,查询他后面的区间有多少个值比他小,则tot+=比他小的数的个数。
这样第一次输出就是初始的逆序对。
其次就是每次操作的时候,要讨论几种情况
1 . x==y||a[x]==a[y]的时候直接输出目前的逆序对数,因为如果交换的话会卡死,并且的确不改变。
2 . x>y的时候要交换x,y;
3 . 如果x+1!=y(等于的时候查也会死循环)则需要讨论四种情况:
情况一 | 将x与y调换后,会增加[x+1,y-1]中比x大的数的个数个逆序对 |
---|
情况二 | 将x与y调换后,会减少[x+1,y-1]中比x小的数的个数个逆序对 |
情况三 | 将x与y调换后,会减少[x+1,y-1]中比y大的数的个数个逆序对 |
情况四 | 将x与y调换后,会增加[x+1,y-1]中比y小的数的个数个逆序对 |
4.最后再讨论x,y的关系,如果a[x]>a[y]则减少一个逆序对,反之增加。
5.输出目前的逆序对的个数,更新x与y位置的值。
后记:这题其实就用到了树套树的排名操作。
代码:
using namespace std ;
struct node
{
int l,r,w,v,size,rnd;
}tr[M];
int n,m,size,ans,tot;
int a[N],root[K];
void make_new(int k)
{
tr[k].size = tr[tr[k].l].size + tr[tr[k].r].size + tr[k].w ;
}
void lturn(int &k)
{
int t = tr[k].r ;
tr[k].r = tr[t].l ;
tr[t].l = k ;
tr[t].size = tr[k].size ;
make_new(k) ;
k = t ;
}
void rturn(int &k)
{
int t = tr[k].l ;
tr[k].l = tr[t].r ;
tr[t].r = k ;
tr[t].size = tr[k].size ;
make_new(k) ;
k = t ;
}
void insert(int &k , int x)
{
if(!k)
{
k = ++size ;
tr[k].size = tr[k].w = 1 ;
tr[k].v = x ;
tr[k].rnd = rand() ;
return ;
}
tr[k].size ++ ;
if(tr[k].v==x){tr[k].w++;return;}
if(x<tr[k].v){insert(tr[k].l,x);if(tr[tr[k].l].rnd<tr[k].rnd){rturn(k);}}
else{insert(tr[k].r,x);if(tr[tr[k].r].rnd<tr[k].rnd){lturn(k);}}
}
void del(int &k , int x)
{
if(tr[k].v==x)
{
if(tr[k].w>1){tr[k].w--;tr[k].size--;return;}
if(tr[k].l*tr[k].r==0)k=tr[k].l+tr[k].r;
else if(tr[tr[k].l].rnd<tr[tr[k].r].rnd){rturn(k);del(k,x);}
else{lturn(k);del(k,x);}
}
else if(x<tr[k].v){del(tr[k].l,x);tr[k].size--;}
else{del(tr[k].r,x);tr[k].size--;}
}
void build(int k,int l,int r,int x,int num)
{
insert(root[k],num) ;
if(l==r)return ;
int mid = (l+r)>>1 ;
if(x<=mid)build(k<<1,l,mid,x,num);
else build(k<<1|1,mid+1,r,x,num);
}
void tr_rk_min(int k,int x)
{
if(!k)return;
if(tr[k].v==x){ans+=tr[tr[k].l].size;return;}
else if(x<tr[k].v)tr_rk_min(tr[k].l,x);
else{ans+=tr[tr[k].l].size+tr[k].w;tr_rk_min(tr[k].r,x);}
}
void a_rk_min(int k,int l,int r,int L,int R,int x)
{
if(L==l&&R==r){tr_rk_min(root[k],x);return;}
int mid=(l+r)>>1;
if(mid>=R)a_rk_min(k<<1,l,mid,L,R,x);
else if(mid<L)a_rk_min(k<<1|1,mid+1,r,L,R,x);
else
{
a_rk_min(k<<1,l,mid,L,mid,x);
a_rk_min(k<<1|1,mid+1,r,mid+1,R,x);
}
}
void tr_rk_max(int k,int x)
{
if(!k)return;
if(tr[k].v==x){ans+=tr[tr[k].r].size;return;}
else if(x<tr[k].v){ans+=tr[tr[k].r].size+tr[k].w;tr_rk_max(tr[k].l,x);}
else{tr_rk_max(tr[k].r,x);}
}
void a_rk_max(int k,int l,int r,int L,int R,int x)
{
if(L==l&&R==r){tr_rk_max(root[k],x);return;}
int mid=(l+r)>>1;
if(mid>=R)a_rk_max(k<<1,l,mid,L,R,x);
else if(mid<L)a_rk_max(k<<1|1,mid+1,r,L,R,x);
else
{
a_rk_max(k<<1,l,mid,L,mid,x);
a_rk_max(k<<1|1,mid+1,r,mid+1,R,x);
}
}
void update(int k,int l,int r,int x,int num,int y)
{
del(root[k],y);
insert(root[k],num);
if(l==r)return;
int mid=(l+r)>>1;
if(x<=mid)update(k<<1,l,mid,x,num,y);
else update(k<<1|1,mid+1,r,x,num,y);
}
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++)scanf("%d",&a[i]);
for(int i=1;i<=n;i++)build(1,1,n,i,a[i]);
for(int i=1;i<=n-1;i++)
{
ans=0;a_rk_min(1,1,n,i+1,n,a[i]);
tot+=ans;
}
printf("%d\n",tot) ;
scanf("%d",&m);
for(int i=1;i<=m;i++)
{
int x,y;
scanf("%d%d",&x,&y);
if(x==y||a[x]==a[y]){printf("%d\n",tot);continue;}
if(x>y)swap(x,y);
if(x+1!=y)
{
ans=0;a_rk_max(1,1,n,x+1,y-1,a[x]);tot+=ans;
ans=0;a_rk_min(1,1,n,x+1,y-1,a[x]);tot-=ans;
ans=0;a_rk_max(1,1,n,x+1,y-1,a[y]);tot-=ans;
ans=0;a_rk_min(1,1,n,x+1,y-1,a[y]);tot+=ans;
}
if(a[x]<a[y])tot++;
else tot--;
update(1,1,n,x,a[y],a[x]);
update(1,1,n,y,a[x],a[y]);
swap(a[x],a[y]);
printf("%d\n",tot) ;
}
}