cogs1715 动态逆序对

1715. [CQOI2011]动态逆序对

输入文件:inverse.in 输出文件:inverse.out 简单对比
时间限制:2 s 内存限制:128 MiB

【题目描述】

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

【输入格式】

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

【输出格式】

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

【样例输入】

  5 4
  1
  5
  3
  4
  2
  5
  1
  4
  2

【样例输出】

  5
  2
  2
  1

样例解释

(1,5,3,4,2)(1,3,4,2)(3,4,2)(3,2)(3)。

【提示】

N<=100000 M<=50000

时间、位置、大小三维偏序
每个数加入后,可能有两种方式构成逆序对,比自己位置靠前但数值小的,比自己位置靠后但数值大的。所以要写两次CDQ。求出的每个数加入后新产生的逆序对的数量。所以还要写一个前缀和。
就这么个东西,写了一天多!水平太差!


/*
    COGS1715:动态逆序对
*/
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int maxn=1e5+10;
const int maxm=5e4+10;
int n,m;
struct node
{
    int pos,x,t;
    bool operator < (const node &a)const
    {
//        if(t!=a.t)return t<a.t;
        if(pos!=a.pos)return pos<a.pos;
        return 0;
    }
}sz[maxn],f[maxn];
int ans[maxm],ansf[maxm];
int tt[maxn];
bool cmp(node a,node b)
{
    if(a.t!=b.t)return a.t<b.t;
    if(a.pos!=b.pos)return  a.pos<b.pos;
}
bool cmpf(node a,node b)
{
    if(a.t!=b.t)return a.t<b.t;
    if(a.pos!=b.pos)return  a.pos>b.pos;
}
int sm[maxn];
void add(int sm[],int pos,int x)
{
    for(int i=pos;i<=n;i+=i&-i)sm[i]+=x;
}
int query(int sm[],int pos)
{
    int ret=0;
    for(int i=pos;i;i-=i&-i)ret+=sm[i];
    return ret;
}
void cdq(int l,int r)
{
    if(l==r)return ;
    int mid=(l+r)>>1;
    cdq(l,mid);
    cdq(mid+1,r);
    int q=l,h=mid+1,p=l;
    while(q<=mid&&h<=r)
    {
        
        if(sz[q].pos<sz[h].pos)//sz[q]时间小,位置前
        {
            f[p]=sz[q];
            add(sm,sz[q].x,1);
            //add(smm,sz[q].x,1);
            //ans[sz[h].t]+=h-mid-query(smm,sz[h].x)-1;
            ++p;++q;
        }
        else//sz[q]时间小,位置后
        {
            f[p]=sz[h];
            ans[sz[h].t]+=q-l-query(sm,sz[h].x);
            ++p;++h;
        }
    }
    while(q<=mid)
    {
         f[p]=sz[q];
            add(sm,sz[q].x,1);
            //add(smm,sz[q].x,1);
            //ans[sz[h].t]+=h-mid-query(smm,sz[h].x)-1;
            ++p;++q;
    }    
    while(h<=r)
    {
        f[p]=sz[h];
            ans[sz[h].t]+=q-l-query(sm,sz[h].x);
            ++p;++h;
    }
    for(int i=l;i<=mid;++i)add(sm,sz[i].x,-1);
//    for(int i=mid+1;i<=r;++i)add(smm,sz[i].x,-1);
    for(int i=l;i<=r;++i)sz[i]=f[i];
}
void cdqf(int l,int r)
{
    if(l==r)return ;
    int mid=(l+r)>>1;
    cdqf(l,mid);
    cdqf(mid+1,r);
    int q=l,h=mid+1,p=l;
    while(q<=mid&&h<=r)
    {
        
        if(sz[q].pos>sz[h].pos)//sz[q]时间小,位置前
        {
            f[p]=sz[q];
            add(sm,sz[q].x,1);
            //add(smm,sz[q].x,1);
            //ans[sz[h].t]+=h-mid-query(smm,sz[h].x)-1;
            ++p;++q;
        }
        else//sz[q]时间小,位置后
        {
            f[p]=sz[h];
            ansf[sz[h].t]+=query(sm,sz[h].x);
            ++p;++h;
        }
    }
    while(q<=mid)
    {
         f[p]=sz[q];
            add(sm,sz[q].x,1);
            //add(smm,sz[q].x,1);
            //ans[sz[h].t]+=h-mid-query(smm,sz[h].x)-1;
            ++p;++q;
    }    
    while(h<=r)
    {
            f[p]=sz[h];
            ansf[sz[h].t]+=query(sm,sz[h].x);
            ++p;++h;
    }
    for(int i=l;i<=mid;++i)add(sm,sz[i].x,-1);
//    for(int i=mid+1;i<=r;++i)add(smm,sz[i].x,-1);
    for(int i=l;i<=r;++i)sz[i]=f[i];
}
signed main()
{
    freopen("inverse.in","r",stdin);
    freopen("inverse.out","w",stdout);
    scanf("%lld%lld",&n,&m);
    for(int i=1;i<=n;++i)
    {
        scanf("%lld",&sz[i].x);
        sz[i].pos=i;
    }
    for(int x,i=1;i<=m;++i)
    {
        scanf("%lld",&x);
        tt[x]=m-i+1;
    }
    for(int i=1;i<=n;++i)sz[i].t=tt[sz[i].x];
    sort(sz+1,sz+1+n,cmp);
    cdq(1,n);
    sort(sz+1,sz+1+n,cmpf);
    cdqf(1,n);
    ans[0]=0;
    for(int i=0;i<=m;++i)ans[i]+=ansf[i];
    for(int i=1;i<=m;++i)ans[i]+=ans[i-1];
 //   printf("%d\n",ans[0]+ansf[0]);
    for(int i=m;i>=1;--i)printf("%lld\n",ans[i]);
    return 0;
}
/*s
3 2
3 1 2
3 1


2
2
*/
原文地址:https://www.cnblogs.com/gryzy/p/15539593.html