#Codeforces 785E(Round404 div2)
题意是初始有一个1,2,3,4....n的序列A,现在有q个操作,每次操作给出两个数L和R,表示交换A[L]和A[R],每次操作后输出当前逆序数的数目。
逆序数的定义是对于两个数A[i],A[j],有A[i]>A[j]且i<j。
那么采取分块法,将n个数,每2048个分成一组,对于每一组内,用树状数组维护。
当交换时,显然,只有在区间[L+1,R-1]内的数的逆序数才会发生改变。
设X=max(A[L],A[R]),Y=min(A[L],A[R]);
那么显然在区间[L+1,R-1]内的数,只有大小在[X+1,Y-1]的范围内的数,逆序数才会发生改变。
为什么?
因为当A[j]>X或者A[j]<Y时, A[L]和A[R]对A[j]来说是没有区别的,所以即便他们两交换位置也不会的A[j]的逆序数产生影响。
那么我们唯一需要处理的就是位置区间[L+1,R-1]且值区间[Y+1,X-1]的数的逆序数的改变。
先处理和A[L-1]同块的数,遍历即可。
再处理和A[R-1]同块的数,遍历即可。
接着处块编号在[blocks(A[L+1])+1,blocks(A[R-1])-1]的块的逆序数。因为每个块由树状数组维护了,sum(X-1)-sum(Y)便能统计出这个块中大于Y小于X的数的个数。
代码参考[http://codeforces.com/profile/liu_cheng_ao](http://codeforces.com/profile/liu_cheng_ao "lca")的AC代码。
题意是初始有一个1,2,3,4....n的序列A,现在有q个操作,每次操作给出两个数L和R,表示交换A[L]和A[R],每次操作后输出当前逆序数的数目。
逆序数的定义是对于两个数A[i],A[j],有A[i]>A[j]且i<j。
那么采取分块法,将n个数,每2048个分成一组,对于每一组内,用树状数组维护。
当交换时,显然,只有在区间[L+1,R-1]内的数的逆序数才会发生改变。
设X=max(A[L],A[R]),Y=min(A[L],A[R]);
那么显然在区间[L+1,R-1]内的数,只有大小在[X+1,Y-1]的范围内的数,逆序数才会发生改变。
为什么?
因为当A[j]>X或者A[j]<Y时, A[L]和A[R]对A[j]来说是没有区别的,所以即便他们两交换位置也不会的A[j]的逆序数产生影响。
那么我们唯一需要处理的就是位置区间[L+1,R-1]且值区间[Y+1,X-1]的数的逆序数的改变。
先处理和A[L-1]同块的数,遍历即可。
再处理和A[R-1]同块的数,遍历即可。
接着处块编号在[blocks(A[L+1])+1,blocks(A[R-1])-1]的块的逆序数。因为每个块由树状数组维护了,sum(X-1)-sum(Y)便能统计出这个块中大于Y小于X的数的个数。
代码参考[http://codeforces.com/profile/liu_cheng_ao](http://codeforces.com/profile/liu_cheng_ao "lca")的AC代码。
#include<bits/stdc++.h>
using namespace std;
#define debug puts("Infinity is awesome!")
#define mm(a,b) memset(a,b,sizeof(a))
#define LS (root<<1)
#define RS (root<<1|1)
#define LSON LS,l,mid
#define RSON RS,mid+1,r
#define LL long long
#define rep(a,b,c) for(int a=b;a<c;a++)
const int Inf=1e9+7;
const int maxn=2e5+5;
const int maxb=(maxn>>11);
const int mod=1e9+7;
int blocks(int x){return x>>11;}
int cnt[maxb+5][maxn];
int a[maxn];
int lowbit(int x){
return x&(-x);
}
void add(int blc,int x,int v){
while(x<maxn){
cnt[blc][x]+=v;
x+=lowbit(x);
}
}
int sum(int blc,int x){
int ret=0;
while(x>0){
ret+=cnt[blc][x];
x-=lowbit(x);
}
return ret;
}
int main(){
LL ans=0;
int n, q;
int l, r;
scanf("%d%d",&n,&q);
for(int i=1;i<=n;i++){
a[i]=i;
add(blocks(i),a[i],1);
}
for(int i=0;i<q;i++){
scanf("%d%d",&l, &r);
if(l==r) {printf("%lld\n",ans); continue; }
if(l>r) swap(l,r);
if(a[l]<a[r]){
ans++;//a[l]<a[r] -> a[r]>a[l], inversions++
if(blocks(l+1)==blocks(r-1)){
for(int j=l+1;j<r;j++)
if(a[j]>a[l]&&a[j]<a[r]) ans+=2;
}
else{
for(int j=l+1;blocks(j)==blocks(l+1);j++)
if(a[j]>a[l]&&a[j]<a[r]) ans+=2;
for(int j=r-1;blocks(j)==blocks(r-1);j--)
if(a[j]>a[l]&&a[j]<a[r]) ans+=2;
for(int j=blocks(l+1)+1;j<blocks(r-1);j++)
ans+=2*((sum(j,a[r]-1))-sum(j,a[l]));
}
}else{
ans--;//a[l]>a[r] -> a[r]<a[l], inversions--
if(blocks(l+1)==blocks(r-1)){
for(int j=l+1;j<r;j++)
if(a[j]<a[l]&&a[j]>a[r]) ans-=2;
}
else{
for(int j=l+1;blocks(j)==blocks(l+1);j++)
if(a[j]<a[l]&&a[j]>a[r]) ans-=2;
for(int j=r-1;blocks(j)==blocks(r-1);j--)
if(a[j]<a[l]&&a[j]>a[r]) ans-=2;
for(int j=blocks(l+1)+1;j<blocks(r-1);j++)
ans-=2*(sum(j,a[l]-1)-sum(j,a[r]));
}
}
add(blocks(l),a[l],-1);
add(blocks(r),a[r],-1);
swap(a[l],a[r]);
add(blocks(l),a[l],1);
add(blocks(r),a[r],1);
printf("%lld\n",ans);
}
return 0;
}