UVA 11990 bit + cdq 分治

来源:互联网 发布:阿里云解析的别名在哪 编辑:程序博客网 时间:2024/05/20 03:39

题意:动态逆序对

做法:对于删除操作可以当做逆向的添加操作 , 所以对于每个数字都有三个属性 (T,ID,Num)  所以这道题其实就是一个三维偏序问题 。 对于一个数 只需要 左边比它大的数 和右边比它小的数 ,我们可以用一个bit logn 进行操作。

三位偏序 可以用CDQ 减去一维 , 我们先把左边算出来 ,再把右边算出来,最后处理中间部分的。

对于中间的部分 用双指针 一个指向 L,MID(时间)。 一个指向MID+1,R(时间) 就可以消除T的影响 ,  同时左右两边满足 id 是递增的!


#include <cstdio>#include <cstring>using namespace std;typedef long long ll;const int maxn=2e5+10;struct node{    int t,num,id;}a[maxn],b[maxn];int n, m;int pos[maxn];ll ans[maxn];int l[maxn],r[maxn],bit[maxn];inline void updata(int pos,int val){    for(int i=pos;i<=n;i+=(i&(-i)) ) bit[i]+=val;}inline int query(int pos){    int ans=0;    for(int i=pos;i;i-=(i&(-i))) ans+=bit[i];    return ans;}inline void cdq(int begin,int end){   if(begin >= end) return;   int mid=(begin+end)>>1;   int l1 = begin ,l2=mid+1,temp;    for(int i=begin;i<=end;++i)    {        if(a[i].t<=mid) b[l1++]=a[i];        else b[l2++]=a[i];    }    for(int i=begin;i<=end;++i) a[i]=b[i];    temp=begin;    for(int i=mid+1;i<=end;++i)    {        for( ; temp<=mid &&a[temp].id<a[i].id;temp++) updata(a[temp].num,1);        l[a[i].t]+=(temp - begin - query(a[i].num));    }    for(int i=begin;i<=temp-1;i++) updata(a[i].num,-1);    temp = mid;    for(int i=end;i>=mid+1;--i)    {        for(; temp>=begin && a[temp].id >a[i].id ; temp--) updata(a[temp].num,1);        r[a[i].t] += query(a[i].num-1);    }    for(int i=temp+1;i<=mid;i++) updata(a[i].num , -1);    cdq(begin,mid); cdq(mid+1,end);}int main(){    while(scanf("%d%d",&n,&m)!=EOF)    {        memset(l,0,sizeof(l));        memset(r,0,sizeof(r));        memset(bit,0,sizeof(bit));        memset(ans,0,sizeof(ans));        for(int i=1;i<=n;++i)        {            scanf("%d",&a[i].num);            a[i].id=i;  a[i].t=0;            pos[a[i].num]=i;        }        int tt=n,x;        for(int i=1;i<=m;++i)        {            scanf("%d",&x);            a[pos[x]].t = tt--;        }        for(int i=1;i<=n;++i)        {            if(a[i].t==0) a[i].t=tt--;        }        cdq(1,n);        for(int i=1;i<=n;++i) ans[i]=ans[i-1] + l[i] + r[i];        for(int i=n;i>=n-m+1;--i) printf("%lld\n",ans[i]);    }    return 0;}