• 刷题总结——动态逆序对(bzoj3295)


    题目:

    Description

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

    Input

    输入第一行包含两个整数nm,即初始元素的个数和删除的元素个数。以下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

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

    HINT

    N<=100000 M<=50000

    Source

    题解:

      同样的一道三维偏序题,将删除看成倒着插入,从而得出:<插入时间,位置,大小>(<t,a,b>),对于一个组数<t,a,b>,找寻(t>t1,a>a1且b<b1)的数量加到对应的ans[t]中,注意最后将ans叠加起来;

      另外要注意在排完t后,a要正着排序求一遍ans然后倒着排序一遍ans,否则ans会少加(想想为什么单纯地求逆序对不用这样)

    代码:

    #include<iostream>
    #include<cstdio>
    #include<cstdlib>
    #include<cmath>
    #include<ctime>
    #include<cctype>
    #include<cstring>
    #include<string>
    #include<algorithm>
    using namespace std;
    const int N=1e5+5;
    struct node
    {
      int t,a,b;
    }q[N],temp[N];
    int n,m,tree[N],to[N],tag[N],tim;
    long long ans[N];
    long long Ans;
    inline int R()
    {
      char c;int f=0;
      for(c=getchar();c<'0'||c>'9';c=getchar());
      for(;c<='9'&&c>='0';c=getchar())
        f=(f<<3)+(f<<1)+c-'0';
      return f;
    }
    inline bool cmp(node a,node b)
    {
      return a.t<b.t;
    }
    inline bool comp(node a,node b)
    {
      return a.a<b.a; 
    }
    inline void insert(int u,int v)
    {
      for(int i=u;i<=n;i+=(i&(-i)))
        if(tag[i]!=tim)  tag[i]=tim,tree[i]=v;
        else tree[i]+=v; 
    }
    inline bool comp2(node a,node b)
    {
      return a.a>b.a;
    }
    inline int query(int u)
    {
      int temp=0;
      for(int i=u;i;i-=(i&(-i)))
        if(tag[i]!=tim)  continue;
        else temp+=tree[i];
      return temp;
    }
    inline void solve1(int l,int r)
    {
      if(l==r)  return;
      int mid=(l+r)/2;
      solve1(l,mid),solve1(mid+1,r);
      int i=l,j=mid+1,k=l;tim++;
      while(i<=mid&&j<=r)
      {
        if(comp(q[i],q[j]))
        {
          insert(q[i].b,1);
          temp[k++]=q[i++];
        }
        else
        {
          ans[q[j].t]+=query(n)-query(q[j].b);
          temp[k++]=q[j++];
        }
      }
      while(i<=mid)  temp[k++]=q[i++];
      while(j<=r)
      {
        ans[q[j].t]+=query(n)-query(q[j].b);
        temp[k++]=q[j++];
      }
      for(j=l;j<=r;j++)  q[j]=temp[j];
     
    }
    inline void solve2(int l,int r)
    {
      if(l==r)  return;
      int mid=(l+r)/2;
      solve2(l,mid),solve2(mid+1,r);
      int i=l,j=mid+1,k=l;tim++;
      while(i<=mid&&j<=r)
      {
        if(comp(q[j],q[i]))
        {
          insert(q[i].b,1);
          temp[k++]=q[i++];
        }
        else
        {
          ans[q[j].t]+=query(q[j].b);
          temp[k++]=q[j++];
        }
      }
      while(i<=mid)  temp[k++]=q[i++];
      while(j<=r)
      {
        ans[q[j].t]+=query(q[j].b);
        temp[k++]=q[j++];
      }
      for(j=l;j<=r;j++)  q[j]=temp[j];
    }
    int main()
    {
    #ifndef ONLINE_JUDGE
      //freopen("a.in","r",stdin);
    #endif
      n=R(),m=R();  
      for(int i=1;i<=n;i++)
      {
        q[i].a=i,q[i].b=R();
        to[q[i].b]=i;
      }
      int Time=n,a;
      for(int i=1;i<=m;i++)
      {
        a=R();q[to[a]].t=Time--;
      }
      for(int i=1;i<=n;i++)
        if(!q[i].t)  q[i].t=Time--;
      sort(q+1,q+n+1,cmp);
      solve1(1,n);
      sort(q+1,q+n+1,cmp); 
      solve2(1,n);
      for(int i=1;i<=n;i++)
        Ans+=ans[i]; 
      for(int i=n;i>n-m;i--)
        printf("%lld
    ",Ans),Ans-=ans[i];
      return 0;
    }
  • 相关阅读:
    博客第一篇:博客申请理由
    Cookie基础
    滚动篇————附一个简单单的自定义滚动条
    javascript中对字符串的操作总结
    javascript中创建对象的几种方式
    javascript中event汇总
    ...python scrapy
    Ubuntu 检测到系统出现问题 弹窗 嘿嘿
    万一哪天笔记全没了, 你真正记住的还有多少
    windows10安装mysql5.7.17是这样安装的吗?
  • 原文地址:https://www.cnblogs.com/AseanA/p/7523002.html
Copyright © 2020-2023  润新知