[CQOI2011]动态逆序对

P1347 - [CQOI2011]动态逆序对

Description

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

Input

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

Hint

样例解释
(1,5,3,4,2)(1,3,4,2)(3,4,2)(3,2)(3)。
数据规模:
N<=100000 , M<=50000

 

把删除看成插入,将每个点赋予一个插入时间,则i的逆序对要满足的条件为:
位置在i前,值比i大,时间比i小;或者位置在i后,值比i小,时间比i小。
然后就可以用
sort+CDQ+树状数组维护三维偏序,注意每个时间的答案要加上前面时间的答案。
  1 #include<set>
  2 #include<map>
  3 #include<queue>
  4 #include<stack>
  5 #include<ctime>
  6 #include<cmath>
  7 #include<string>
  8 #include<vector>
  9 #include<cstdio>
 10 #include<cstdlib>
 11 #include<cstring>
 12 #include<iostream>
 13 #include<algorithm>
 14 #define maxn 100010
 15 using namespace std;
 16 struct data{
 17   int x,y,z,ans1,ans2;
 18 }f[maxn];
 19 int tree[maxn],co[maxn],LOL=0;
 20 long long ans[maxn];
 21 int lowbit(int x){return x&-x;}
 22 void add(int p,int v){
 23   for(int i=p;i<maxn;i+=lowbit(i)){
 24     if(co[i]!=LOL) tree[i]=0;
 25     co[i]=LOL;
 26     tree[i]+=v;
 27   }
 28 }
 29 int find(int p){
 30   int ret=-0;
 31   for(int i=p;i;i-=lowbit(i))
 32     if(co[i]==LOL) ret+=tree[i];
 33   return ret;
 34 }
 35 bool cmpcdq1(const data &a,const data &b){
 36   if(a.y!=b.y) return a.y>b.y;
 37   else return a.z<b.z;
 38 }
 39 bool cmpcdq2(const data &a,const data &b){
 40   if(a.y!=b.y) return a.y<b.y;
 41   else return a.z<b.z;
 42 }
 43 void CDQ1(int l,int r){
 44   if(l==r) return;
 45   int mid=(l+r)>>1;
 46   CDQ1(l,mid),CDQ1(mid+1,r);
 47   sort(f+l,f+mid+1,cmpcdq1),sort(f+mid+1,f+r+1,cmpcdq1);
 48   LOL++;
 49   for(int j=mid+1,i=l;j<=r;j++){
 50     for(;f[i].y>f[j].y&&i<=mid;i++)
 51       add(f[i].z,1);
 52     f[j].ans1+=find(f[j].z);
 53   }
 54 }
 55 void CDQ2(int l,int r){
 56   if(l==r) return;
 57   int mid=(l+r)>>1;
 58   CDQ2(l,mid),CDQ2(mid+1,r);
 59   sort(f+l,f+mid+1,cmpcdq2),sort(f+mid+1,f+r+1,cmpcdq2);
 60   LOL++;
 61   for(int j=mid+1,i=l;j<=r;j++){
 62     for(;f[i].y<f[j].y&&i<=mid;i++)
 63       add(f[i].z,1);
 64     f[j].ans2+=find(f[j].z);
 65   }
 66 }
 67 bool cmmp(const data &a,const data &b){
 68   return a.y<b.y;
 69 }
 70 bool cmmmp(const data &a,const data &b){
 71   return a.x<b.x;
 72 }
 73 bool cmmmp1(const data &a,const data &b){
 74   return a.x>b.x;
 75 }
 76 int main()
 77 {
 78   freopen("!.in","r",stdin);
 79   freopen("!.out","w",stdout);
 80   int n,m,sp;scanf("%d%d",&n,&m);
 81   for(int i=1;i<=n;i++)
 82     scanf("%d",&f[i].y),f[i].x=i;
 83   sort(f+1,f+n+1,cmmp);
 84   int cnt=m+1;
 85   for(int i=1;i<=m;i++)
 86     scanf("%d",&sp),f[sp].z=cnt,cnt--;
 87   for(int i=1;i<=n;i++)
 88     if(!f[i].z)f[i].z=1;
 89   sort(f+1,f+n+1,cmmmp);
 90   CDQ1(1,n);
 91   LOL=0;memset(co,0,sizeof(co));
 92   sort(f+1,f+n+1,cmmmp1);
 93   CDQ2(1,n);
 94   for(int i=1;i<=n;i++)
 95     ans[f[i].z]+=f[i].ans1+f[i].ans2;
 96   ans[1]/=2;
 97   for(int i=2;i<=m+1;i++)
 98     ans[i]+=ans[i-1];
 99   for(int i=m+1;i>=2;i--)
100     printf("%lld\n",ans[i]);
101   return 0;
102 }

 

 
posted @ 2017-04-01 22:49  嘘丶  阅读(261)  评论(0编辑  收藏  举报