bzoj3295[Cqoi2011]动态逆序对 cdq分治(树套树/主席树)

来源:互联网 发布:潜在客户软件 编辑:程序博客网 时间:2024/06/07 13:18

这题应该挺老了吧,好多人都切了,各种姿势都有,cdq分治是比较简单的一种,我就打了。。
跟普通的偏序不同,这里有一个删除的操作,那么我们其实可以把删除看作倒着插入,然后对被删除的哪一个数标记一下被删除的时间,然后对序列中的每一个数加上一维限制t,表示时间,那么明显对于未删除的,他们的时间按顺序递增,否则就从n递减,因为第一个删除就是最后一个插入。
然后就是三维偏序裸题了,注意一下要正反各扫1遍,计算上所有贡献。

#include<cstdio>#include<algorithm>#include<cstring>#include<iostream>#define fo(i,a,b) for(int i=a;i<=b;i++)#define fd(i,a,b) for(int i=a;i>=b;i--)using namespace std;const int N=1e5+5;int n,m; typedef long long ll;int pos[N];bool vis[N];ll ans[N];struct code{    int t,x,y;    bool flag;    bool operator < (const code &a) const    {        if (a.t!=t)return t<a.t;        if (a.x!=x)return x<a.x;        return y>a.y;    }}a[N],b[N];int c[N];int lowbit(int x){    return x&(-x);}bool cmpx(code a,code b){    if (a.x!=b.x)return a.x<b.x;    if (a.y!=b.y)return a.y<b.y;    return a.t<b.t;}inline void add(int x,int y){    while (x<=n)    {        c[x]+=y;        x+=lowbit(x);    }}inline int find(int x){    int ret=0;    while (x>0)    {        ret+=c[x];        x-=lowbit(x);    }    return ret;}inline void cdq(int l,int r){    if (l>=r)return;    int mid=(l+r)>>1;    cdq(l,mid),cdq(mid+1,r);    int cnt=0;    fo(i,l,r)    {        b[++cnt]=a[i];        if (i>mid)b[cnt].flag=1;    }    sort(b+1,b+1+cnt,cmpx);    fo(i,1,cnt)    {        if (b[i].flag==0)add(b[i].y,1);        else ans[b[i].t]+=find(n)-find(b[i].y);    }    fo(i,1,cnt)if (!b[i].flag)add(b[i].y,-1);    fd(i,cnt,1)    {            if (b[i].flag==0)add(b[i].y,1);        else ans[b[i].t]+=find(b[i].y);    }     fo(i,1,cnt)if (!b[i].flag)add(b[i].y,-1);}int main(){    scanf("%d%d",&n,&m);    int tot=n;    fo(i,1,n)scanf("%d",&a[i].y),a[i].x=i,pos[a[i].y]=i;    fo(i,1,m)    {        int x;        scanf("%d",&x);        x=pos[x];        vis[x]=1;        a[x].t=tot--;     }    fd(i,n,1)    if (!vis[i])a[i].t=tot--;    sort(a+1,a+1+n);    cdq(1,n);    ll ans1=0;    fo(i,1,n)ans1+=ans[i];    fd(i,n,n-m+1)    {        printf("%lld\n",ans1);        ans1-=ans[i];    }} 
阅读全文
0 0