[BZOJ3295][Cqoi2011]动态逆序对

3295: [Cqoi2011]动态逆序对

Time Limit: 10 Sec  Memory Limit: 128 MB
Submit: 5276  Solved: 1783
[Submit][Status][Discuss]

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

 

cdq分治裸题。

首先我们把删除改为倒序插入,对于每一个操作,我们记录三元组(x,y,z)表示位置为x数值为y操作时间为z。此时,我们要求对于每一个(x,y,z)的z0<z&&x0<x&&y0》y。

我们首先考虑对于z从小到大排序,这样,我们就能忽略z的影响。此时,我们要求x0<x&&y0>y的组数。

现在我们开始分治。

首先对于区间(l,r),区间(l,mid)中所有元素的z都小于(mid+1,r)中所有元素的z,所以我们考虑(l,mid)中的修改对(mid+1,r)中的每个元素的影响。

现在我们对区间(l,mid)中的所有元素打上标记,使其成为修改操作,对于区间(mid+1,r)中的所有元素打上标记,使其成为询问操作。

我们对区间(l,r)以x为第一关键字排序,这样,我们要求的就是a[i].y<a[j].y(i>j) a[i].y>a[j].y(i<j)的个数,可以用树状数组维护。

处理完区间(l,r),我们可以分治处理(l,mid)(mid+1,r)

 1 #include<iostream>
 2 #include<cstring>
 3 #include<cstdio>
 4 #include<cstdlib>
 5 #include<cmath>
 6 #include<algorithm>
 7 using namespace std;
 8 int n,m;
 9 struct data
10 {
11     int x,y,z;
12     int flag;
13 }a[100008],b[100008];
14 int w[100008];
15 bool cmp1(data s1,data s2){return s1.z<s2.z;}
16 bool cmp2(data s1,data s2){return s1.x<s2.x;}
17 int tre[100008];
18 long long ans[100008];
19 int lowbit(int x){return x&(-x);}
20 void update(int x,int ad){for(int i=x;i<=n;i+=lowbit(i)) tre[i]+=ad;}
21 int query(int x)
22 {
23     int re=0;
24     for(int i=x;i>0;i-=lowbit(i)) re+=tre[i];
25     return re;
26 }
27 void cdq(int l,int r)
28 {
29     if(l>=r) return;
30     int mid=(l+r)>>1;
31     int cnt=0;
32     for(int i=l;i<=r;i++)
33     {
34         if(i<=mid){b[++cnt]=a[i];b[cnt].flag=0;}
35         else {b[++cnt]=a[i];b[cnt].flag=1;}
36     }
37     sort(b+1,b+cnt+1,cmp2);
38     for(int i=1;i<=cnt;i++)
39     {
40         if(!b[i].flag) update(b[i].y,1);
41         else ans[b[i].z]+=(long long)(query(n)-query(b[i].y));
42     }
43     for(int i=1;i<=cnt;i++) if(!b[i].flag) update(b[i].y,-1);
44     for(int i=cnt;i>=1;i--)
45     {
46         if(!b[i].flag) update(b[i].y,1);
47         else ans[b[i].z]+=(long long)query(b[i].y);
48     }
49     for(int i=1;i<=cnt;i++) if(!b[i].flag) update(b[i].y,-1);
50     cdq(l,mid); cdq(mid+1,r);
51 }
52 int main()
53 {
54     scanf("%d%d",&n,&m);
55     int c=n;
56     for(int i=1;i<=n;i++)
57     {
58         a[i].x=i;scanf("%d",&a[i].y);w[a[i].y]=i;
59     }
60     for(int i=1;i<=m;i++)
61     {
62         int t;
63         scanf("%d",&t);
64         a[w[t]].z=c--;
65     }
66     for(int i=n;i>=1;i--) if(!a[i].z) a[i].z=c--;
67     sort(a+1,a+n+1,cmp1);
68     cdq(1,n);
69     for(int i=1;i<=n;i++) ans[i]+=ans[i-1];
70     for(int i=n;i>=n-m+1;i--) printf("%lld\n",ans[i]);
71 }
View Code

 

posted @ 2017-08-18 11:43  wls001  阅读(158)  评论(0编辑  收藏  举报