刷题总结——动态逆序对(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\n",Ans),Ans-=ans[i];
  return 0;
}

 

posted @ 2017-09-14 21:06  AseanA  阅读(204)  评论(0编辑  收藏  举报