【cdq分治】[HYSBZ/BZOJ3295]动态逆序对

来源:互联网 发布:js隐藏显示div 编辑:程序博客网 时间:2024/05/17 23:13

题目

看看这篇博客写的时间,BZOJ已经挂了,我就不粘BZOJ链接了。

Description

对于序列A,它的逆序对数定义为满足i < j,且Ai > Aj的数对(i,j)的个数。给1到n的一个排列,按照某种顺序依次删除m个元素,你的任务是在每次删除一个元素之前统计整个序列的逆序对数。

Input

输入第一行包含两个整数n和m,即初始元素的个数和删除的元素个数。以下n行每行包含一个1到n之间的正整数,即初始排列。以下m行每行一个正整数,依次为每次删除的元素。

Output

输出包含m行,依次为删除每个元素之前,逆序对的个数。

Sample Input

5 4
1
5
3
4
2
5
1
4
2
Sample Output

5
2
2
1
Hint

样例解释
(1,5,3,4,2)>>(1,3,4,2)>>(3,4,2)>>(3,2)>>(3)。

数据范围

编号 1-2 3-4 5-6 7-8 9-10

n <=1000 <=30000 <=50000 <=60000 <=100000

m <=100 <=10000 <=20000 <=40000 <=50000

分析

这道题

我们令y表示当前数字,t表示y被加入(先被删除的后加入)的时间,x表现y在原串中的位置,这样一个数字就变成了一个三元组(t,x,y)。
不难发现,当一个数字(t0,x0,y0)对最终的逆序对数作出的贡献为存在的三元组(t,x,y)使得(t<t0,(x<x0)xor(y<y0)==1)的数量。
这样,我们就可以用cdq分治做这道题。
如果你已经会cdq请直接看代码。

如何用cdq分治做这道题

This part was powered by azui
t<t0,x<x0,y>y0或者t<t0,x>x0,y<y0
我们先考虑满足条件一:t<t0,x<x0,y>y0的点。
在外面按x排序后,还剩下t,y两个参数。我们可以对t进行划分排序,使得t,x满足这里写图片描述
然后就可以求出对于每一个右边的三元组(t0,x0,y0),有多少个点满足t<t0,x<x0(类似于归并排序),然后用树状数组维护这些三元组中有哪些y>y0
条件二类似。
然后递归处理左右两边。

感谢azui大神,你们也可以去看他自己的博客

代码

#include<cstdio>#include<algorithm>#define MAXN 100000using namespace std;struct node{    int t,x,y;    node(){    }    node(int tt,int xx,int yy){        t=tt,x=xx,y=yy;    }}p[MAXN+10],tmp[MAXN+10];int n,m,a[MAXN+10],t[MAXN+10],c[MAXN+10];long long ans[MAXN+10];void Read(int &x){    char c;    while(c=getchar(),c!=EOF)        if(c>='0'&&c<='9'){            x=c-'0';            while(c=getchar(),c>='0'&&c<='9')                x=x*10+c-'0';            ungetc(c,stdin);            return;        }}inline int lowbit(int x){    return x&-x;}void update(int x,int d){    while(x<=n){        c[x]+=d;        x+=lowbit(x);    }}int get_sum(int x){    int ret=0;    while(x){        ret+=c[x];        x-=lowbit(x);    }    return ret;}void read(){    Read(n),Read(m);    int i,b,j=0;    for(i=1;i<=n;i++)        Read(a[i]);    for(i=1;i<=m;i++){        Read(b);        t[b]=i;    }    for(i=1;i<=n;i++)        if(t[a[i]])            p[i]=node(n-t[a[i]]+1,i,a[i]);        else            p[i]=node(++j,i,a[i]);}void cdq(int l,int r){    if(l==r)        return;    int mid=(l+r)>>1,i,j,k;    k=mid+1,j=l;    for(i=l;i<=r;i++)        if(p[i].t<=mid)            tmp[j++]=p[i];        else            tmp[k++]=p[i];    for(i=l;i<=r;i++)        p[i]=tmp[i];    i=l;    for(j=mid+1;j<=r;j++){        for(;i<=mid&&p[i].x<p[j].x;i++)            update(p[i].y,1);        ans[p[j].t]+=(i-l)-get_sum(p[j].y);    }    for(i--;i>=l;i--)        update(p[i].y,-1);    i=mid;    for(j=r;j>mid;j--){        for(;i>=l&&p[i].x>p[j].x;i--)            update(p[i].y,1);        ans[p[j].t]+=get_sum(p[j].y);    }    for(i++;i<=mid;i++)        update(p[i].y,-1);    cdq(l,mid);    cdq(mid+1,r);}void print(){    int i;    for(i=2;i<=n;i++)        ans[i]+=ans[i-1];    for(i=n;i>n-m;i--)        printf("%I64d\n",ans[i]);}int main(){    read();    cdq(1,n);    print();}
0 0