BZOJ3295: [Cqoi2011]动态逆序对

Posted ONION_CYC

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了BZOJ3295: [Cqoi2011]动态逆序对相关的知识,希望对你有一定的参考价值。

【题意】给定1~n的排列,m次操作每次删除一个数,求每次操作前的逆序对数。n<=10^5,m<=50000。

【算法】CDQ分治+树状数组

【题解】先树状数组求逆序对,然后统计每次删除的逆序对数。

每个数字及其坐标构成一个二维坐标,逆序对就是两个相对位置在左上右下的点,那么删除一个点会减少的逆序对就是其左上偏序和右下偏序中的点数,转化为有操作顺序的二维平面矩阵查询和单点修改,用CDQ分治或树套树解决。

具体细节:

1.先加入所有加点操作(原数字必须作为最开始的操作进入CDQ分治过程),再加入前m-1个删除和询问。

2.第一次统计右下偏序,按x轴逆序排序后CDQ分治。

3.第二次统计左上偏序,令所有点y=n-y+1,然后按x轴正序排序后CDQ分治。

技术分享图片
#include<cstdio>
#include<cctype>
#include<cstring>
#include<algorithm>
#define lowbit(x) (x&-x)
using namespace std;
int read(){
    char c;int s=0,t=1;
    while(!isdigit(c=getchar()))if(c==-)t=-1;
    do{s=s*10+c-0;}while(isdigit(c=getchar()));
    return s*t;
}
const int maxn=100010;
int n,m,ans[maxn],c[maxn],t[maxn],A[maxn],tot=0;
struct cyc{int id,kind,qid,x,y;}a[maxn*2],b[maxn*2];
long long ANS=0;
void modify(int x,int k){for(int i=x;i<=n;i+=lowbit(i))c[i]+=k;}
int query(int x){int as=0;for(int i=x;i>=1;i-=lowbit(i))as+=c[i];return as;}
bool cmp(cyc a,cyc b){return a.x<b.x||(a.x==b.x&&a.id<b.id);}
bool cmp2(cyc a,cyc b){return a.x>b.x||(a.x==b.x&&a.id<b.id);}
void CDQ(int l,int r){
    if(l==r)return;
    int mid=(l+r)>>1;
    for(int i=l;i<=r;i++){
        if(a[i].id<=mid&&!a[i].kind)modify(a[i].y,a[i].qid?-1:1);
        if(a[i].id>mid&&a[i].kind)ans[a[i].qid]+=query(a[i].y);
    }
    for(int i=l;i<=r;i++)if(a[i].id<=mid&&!a[i].kind)modify(a[i].y,a[i].qid?1:-1);
    int x1=l-1,x2=mid;
    for(int i=l;i<=r;i++)if(a[i].id<=mid)b[++x1]=a[i];else b[++x2]=a[i];
    for(int i=l;i<=r;i++)a[i]=b[i];
    CDQ(l,mid);CDQ(mid+1,r);
}    
int main(){
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++){
        A[i]=read();
        t[A[i]]=i;
        modify(A[i],1);
        ANS+=i-query(A[i]);
    }
    if(m>1)printf("%lld\n",ANS);
    memset(c,0,sizeof(c));
    for(int i=1;i<=n;i++)a[++tot]=(cyc){tot,0,0,i,A[i]};
    for(int i=1;i<m;i++){
        int x=read();
        a[++tot]=(cyc){tot,0,i,t[x],x};
        a[++tot]=(cyc){tot,1,i,t[x],x};
    }
    sort(a+1,a+tot+1,cmp2);
    CDQ(1,tot);
    for(int i=1;i<=tot;i++)a[i].y=n-a[i].y+1;
    sort(a+1,a+tot+1,cmp);
    CDQ(1,tot);
    for(int i=1;i<m;i++){
        ANS-=ans[i];
        printf("%lld\n",ANS);
    }
    return 0;
}
View Code

 

以上是关于BZOJ3295: [Cqoi2011]动态逆序对的主要内容,如果未能解决你的问题,请参考以下文章

BZOJ#3295. [Cqoi2011]动态逆序对

bzoj3295: [Cqoi2011]动态逆序对

[BZOJ3295][Cqoi2011]动态逆序对

bzoj3295[Cqoi2011]动态逆序对 树套树

bzoj3295 Cqoi2011—动态逆序对

BZOJ3295[Cqoi2011]动态逆序对 cdq分治