bzoj 3295 动态逆序对 CDQ分治

来源:互联网 发布:淘宝源码 编辑:程序博客网 时间:2024/05/16 13:22

每删除一个数对答案的影响是 前面比他大的数的个数+后面比他小的数的个数。问题变成了插入一个数并求出前面有多少数比他大(后面小的数可以用同样方法求)。
首先这可以用一个二维数据结构做。
CDQ分治的强大之处在于它能够压掉一维。它的主要思想是把操作分为两部分,计算前半部分修改对后半部分询问影响,然后递归处理两部分。
我这个代码写的太丑了,调了一天,,,还不如去写树套树>_<。

#include<cstdio>#include<cstdlib>#include<cstring>#include<iostream>#include<algorithm>#define maxn 200005#define LL long longusing namespace std;int a[maxn],pos[maxn];int q[maxn];LL ans[maxn];struct BT{    LL c[maxn];int N;    int lowbit(int x){return (x&(-x));}    void add(int x,int d)    {        for(;x<=N;x+=lowbit(x))            c[x]+=d;    }    LL ask(int x)    {        LL ans=0;        for(;x>0;x-=lowbit(x))ans+=c[x];        return ans;    }}B;int n,m;struct SZS{    int val,id;}L[maxn],R[maxn];bool cmps(SZS A,SZS B){   return A.val<B.val;}void solve(int l,int r){    if(l==r) return ;    int mid=l+r>>1;    for(int i=l;i<=mid;i++)  L[i-l+1].val=q[i],L[i-l+1].id=i;    for(int i=mid+1;i<=r;i++)R[i-mid].val=q[i],R[i-mid].id=i;    int len1=mid-l+1,len2=r-mid;    sort(L+1,L+len1+1,cmps);sort(R+1,R+len2+1,cmps);    int H1=1,H2=1;    while(H1<=len1||H2<=len2)    {        if(H2>len2||(H1<=len1&&L[H1].val<R[H2].val))            B.add(a[L[H1++].val],1);        else ans[R[H2].id]+=B.ask(n)-B.ask(a[R[H2].val]),H2++;    }    for(int i=1;i<=len1;i++)        B.add(a[L[i].val],-1);    solve(l,mid);solve(mid+1,r);}bool use[maxn];int tmp[maxn];LL ANS;void init(){    memset(use,0,sizeof(use));    for(int i=1;i<=m;i++) use[q[i]]=1;    for(int i=1;i<=n;i++) tmp[i]=0;    for(int i=1;i<=n;i++)        if(!use[i])        {            ANS+=B.ask(n)-B.ask(a[i]);            B.add(a[i],1);        }        else tmp[i]=B.ask(n)-B.ask(a[i]);    for(int i=1;i<=n;i++)        if(!use[i]) B.add(a[i],-1);    for(int i=1;i<=m;i++)        ans[i]+=tmp[q[i]];}int main(){    int x;    scanf("%d%d",&n,&m);    B.N=n;    for(int i=1;i<=n;i++)        scanf("%d",&a[i]),pos[a[i]]=i;    for(int i=1;i<=m;i++)        scanf("%d",&x),q[i]=pos[x];    for(int i=1;i<=m/2;i++)        swap(q[i],q[m-i+1]);    init();    solve(1,m);LL P=ANS;    for(int i=1;i<=n/2;i++)swap(a[i],a[n-i+1]);    for(int i=1;i<=m;i++) q[i]=n-q[i]+1;    for(int i=1;i<=n;i++) a[i]=n-a[i]+1;    init();    solve(1,m);    for(int i=1;i<=m;i++)        P+=ans[i];    for(int i=m;i>=1;i--)    {        printf("%lld\n",P);        P-=ans[i];    }    return 0;}
1 0
原创粉丝点击