BZOJ2141 排队 分块+树状数组

题意:给定一个数列,每次交换两个数后,输出序列中逆序对的数量。

题解:

比树套树神马的好写了多了,虽然时间理论上应该慢一些,但是绝不会MLE

首先我们离散化,由于交换(x,y)只会对(x,y)之间的数产生影响,因此我们讨论x<i<y

a[i]<a[x] --ans

a[i]>a[x] ++ans

a[i]<a[y] ++ans

a[i]>a[y] --ans

我们用树状数组来维护每个块内每个数出现的次数,最后别忘了讨论a[x]和a[y]。

#include <cmath>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>
using namespace std;
#define lowbit(x) (x&(-x))

const int MAXS=200+2;
const int MAXN=20000+2;
struct BLOCK{
    int a[MAXS],b[MAXN];
}block[MAXS];
int N,M,S,C,U,b[MAXN],ans;
pair<int,int> num[MAXN];

void Add(int p,int x,int v){
    while(x<=U) block[p].b[x]+=v,x+=lowbit(x);
}

int Sum(int p,int x){
    int ret=0;
    while(x) ret+=block[p].b[x],x-=lowbit(x);
    return ret;
}

int main(){
    scanf("%d",&N);
    S=ceil(sqrt((double)N)),C=(N-1)/S+1;
    for(int i=1;i<=N;i++){
        scanf("%d",&num[i].first);
        num[i].second=i;
    }
    sort(num+1,num+N+1);
    for(int i=1;i<=N;i++){
        if(num[i].first!=num[i-1].first) U++;
        block[(num[i].second-1)/S+1].a[num[i].second-(num[i].second-1)/S*S]=U;
    }
    for(int i=1;i<=C;i++)
        for(int j=1;j<=S && j+(i-1)*S<=N;j++){
            Add(i,block[i].a[j],1);

            for(int k=block[i].a[j];k<=U;k+=lowbit(k)) b[k]++;
            for(int k=U;k;k-=lowbit(k)) ans+=b[k];
            for(int k=block[i].a[j];k;k-=lowbit(k)) ans-=b[k];
        }
    printf("%d\n",ans);

    scanf("%d",&M);
    for(int i=1,x,y,a,b,l,r;i<=M;i++){
        scanf("%d %d",&x,&y);
        if(x>y) swap(x,y);
        l=x,r=y;

        a=block[(x-1)/S+1].a[x-(x-1)/S*S],b=block[(y-1)/S+1].a[y-(y-1)/S*S];
        x++,y--;
        if((x-1)%S){
            int p=(x-1)/S+1;
            for(int j=x-(p-1)*S;j<=S && j<=y-(p-1)*S;j++){
                if(block[p].a[j]<a) ans--;
                if(block[p].a[j]>a) ans++;
                if(block[p].a[j]<b) ans++;
                if(block[p].a[j]>b) ans--;
            }
            x=p*S+1;
        }

        while(x+S-1<=y){
            ans-=Sum(x/S+1,a-1),ans+=Sum(x/S+1,U)-Sum(x/S+1,a);
            ans+=Sum(x/S+1,b-1),ans-=Sum(x/S+1,U)-Sum(x/S+1,b);
            x+=S;
        }
        if(y%S){
            int p=x/S+1;
            for(int j=1;j<=y-(p-1)*S;j++){
                if(block[p].a[j]<a) ans--;
                if(block[p].a[j]>a) ans++;
                if(block[p].a[j]<b) ans++;
                if(block[p].a[j]>b) ans--;
            }
        }
        if(a>b) ans--;
        if(a<b) ans++;

        printf("%d\n",ans);
        Add((l-1)/S+1,a,-1),Add((r-1)/S+1,b,-1);
        swap(block[(l-1)/S+1].a[l-(l-1)/S*S],block[(r-1)/S+1].a[r-(r-1)/S*S]);
        Add((l-1)/S+1,b,1),Add((r-1)/S+1,a,1);
    }

    return 0;
}
View Code

 

posted @ 2017-02-27 00:32  WDZRMPCBIT  阅读(138)  评论(0编辑  收藏  举报