bzoj2141: 排队

来源:互联网 发布:360全景展示软件 编辑:程序博客网 时间:2024/04/28 20:16

链接: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;}/*3130 150 14022 31 3778 976 321 108 3 2 3101 42 57 31 73 62 15 71 43 64 2*/


0 0
原创粉丝点击