bzoj2141: 排队

链接:http://www.lydsy.com/JudgeOnline/problem.php?id=2141

题意:中文题。

分析:先将数组离散化一下,然后对于每一次交换考虑两个元素改变是对逆序对总和的影响就好了,在查找当前值x对逆序对总和影响时分3中情况,第一种是和x在同一个块内的数,sqrt(n)扫一遍即可,第二种是在x所在的块前面的块内,第三种是在x所在的块后面的块内,在块内的个数二分即可,记得在改变的时候要将被改变的那个块重构一下。

代码:

#include<map>
#include<set>
#include<cmath>
#include<queue>
#include<math.h>
#include<cstdio>
#include<vector>
#include<string>
#include<cstring>
#include<iostream>
#include<algorithm>
#pragma comment(linker, "/STACK:102400000,102400000")
using namespace std;
const int N=20010;
const int MAX=151;
const int MOD=1000000007;
const int MOD1=100000007;
const int MOD2=100000009;
const int INF=1000000000;
const double EPS=0.00000001;
typedef long long ll;
typedef unsigned long long ull;
int read()
{
    int x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    return x*f;
}
int k,n,clo,ans,f[N];
int b[N],c[N],d[N];
struct node {
    int u,v;
}a[N];
int cmd(node x,node y) {
    return x.u<y.u;
}
void init() {
    scanf("%d", &n);
    for (int i=1;i<=n;i++) {
        scanf("%d", &a[i].u);a[i].v=i;
    }
    clo=(int)sqrt(n);
    k=a[0].u=a[0].v=0;
    sort(a,a+n+1,cmd);
    for (int i=1;i<=n;i++)
    if (a[i].u==a[i-1].u) d[a[i].v]=k;
    else d[a[i].v]=++k;
    for (int i=1;i<=n;i++) { b[i]=d[i];c[i]=(i+clo-1)/clo; }
    for (int i=1;i<=n/clo;i++) sort(b+(i-1)*clo+1,b+i*clo+1);
    sort(b+n/clo*clo+1,b+n+1);
}
int get(int x) {
    int ret=0;
    for (;x;x-=x&(-x)) ret+=f[x];
    return ret;
}
void add(int x,int y) {
    for (;x<=k;x+=x&(-x)) f[x]+=y;
}
void deal() {
    ans=0;memset(f,0,sizeof(f));
    for (int i=1;i<=n;i++) {
        add(d[i],1);ans+=i-get(d[i]);
    }
    printf("%d\n", ans);
}
int getbig(int i,int x) {
    int l=(i-1)*clo,r,w,mid;
    if (i==n/clo+1) { r=n+1;w=n; }
    else { r=i*clo+1;w=i*clo; }
    mid=(l+r)/2;
    while (l+1<r)
    if (b[mid]<=x) { l=mid;mid=(l+r)/2; }
    else { r=mid;mid=(l+r)/2; }
    return w-l;
}
int getsmall(int i,int x) {
    int l=(i-1)*clo,r,w,mid;
    if (i==n/clo+1) { r=n+1;w=l; }
    else { r=i*clo+1;w=l; }
    mid=(l+r)/2;
    while (l+1<r)
    if (b[mid]<x) { l=mid;mid=(l+r)/2; }
    else { r=mid;mid=(l+r)/2; }
    return l-w;
}
int getn(int x) {
    int i,l=(c[x]-1)*clo+1,r,ret=0;
    if (c[x]==n/clo+1) r=n;
    else r=c[x]*clo;
    for (i=l;i<x;i++)
    if (d[i]>d[x]) ret++;
    for (i=x+1;i<=r;i++)
    if (d[i]<d[x]) ret++;
    for (i=1;i<c[x];i++) ret+=getbig(i,d[x]);
    for (i=c[x]+1;i<=n/clo+1;i++) ret+=getsmall(i,d[x]);
    return ret;
}
void change(int x) {
    int i,l=(x-1)*clo+1,r;
    if (x==n/clo+1) r=n;
    else r=x*clo;
    for (i=l;i<=r;i++) b[i]=d[i];
    sort(b+l,b+r+1);
}
void quiry() {
    int m,x,y,yx,yy;
    scanf("%d", &m);
    while (m--) {
        scanf("%d%d", &x, &y);
        if (x>y) swap(x,y);
        yx=d[x];yy=d[y];
        if (yx==yy) printf("%d\n", ans);
        else {
            ans-=getn(x);ans-=getn(y);
            if (d[x]>d[y]) ans++;
            d[x]=yy;change(c[x]);
            d[y]=yx;change(c[y]);
            ans+=getn(x);ans+=getn(y);
            if (d[x]>d[y]) ans--;
            printf("%d\n", ans);
        }
    }
}
int main()
{
    init();
    deal();
    quiry();
    return 0;
}
/*
3
130 150 140
2
2 3
1 3
7
78 976 321 108 3 2 3
10
1 4
2 5
7 3
1 7
3 6
2 1
5 7
1 4
3 6
4 2
*/


你可能感兴趣的:(bzoj2141: 排队)