bzoj3295 [Cqoi2011]动态逆序对 cdq+树状数组

【bzoj3295】[Cqoi2011]动态逆序对

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

 

题解:

    这道动态逆序对问题和普通逆序对问题有什么区别,发现动态逆序对的每个值还有一个时间影响

    普通逆序对只有两个元素是二维偏序问题,一维是位置,一维是键值。

    而这里就是三维偏序问题,我们应该怎么来安排可以最方便呢?

    我是这样安排的,a,b,c分别表示时间,位置,键值,分别排序+cdq+树状数组,这样来搞

    在对于键值中,有点技巧,应为位置可能在前或者在后面,所以两次树状数组维护才行。

    最后用前缀和的思想。

 1 #include<cstring>
 2 #include<cmath>
 3 #include<algorithm>
 4 #include<iostream>
 5 #include<cstdio>
 6 
 7 #define N 100007
 8 using namespace std;
 9 inline int read()
10 {
11     int x=0,f=1;char ch=getchar();
12     while(ch<'0'||ch>'9'){if (ch=='-')f=-1;ch=getchar();}
13     while(ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();}
14     return x*f;
15 }
16 
17 int n,m,tr[N];
18 long long ans[N];
19 struct Node
20 {
21     int a,b,c,ans;
22 }a[N];
23 
24 bool cmp1(Node x,Node y)
25 {
26     if (x.a==y.a&&x.b==y.b) return x.c>y.c;
27     if (x.a==y.a) return x.b<y.b;
28     return x.a<y.a;
29 }
30 bool cmp2(Node x,Node y)
31 {
32     return x.b<y.b;
33 }
34 bool cmp3(Node x,Node y)
35 {
36     return x.b>y.b;
37 }
38 int lowbit(int x){return x&(-x);}
39 void update(int x,int num)
40 {
41     for (int i=x;i<=n;i+=lowbit(i))
42         tr[i]+=num;
43 }
44 int query(int x)
45 {
46     int res=0;
47     for (int i=x;i>=1;i-=lowbit(i))
48         res+=tr[i];
49     return res;    
50 }
51 void cdq(int l,int r)
52 {
53     if (l==r) return;
54     int mid=(l+r)>>1;
55     cdq(l,mid);
56     cdq(mid+1,r);
57     sort(a+l,a+mid+1,cmp2);
58     sort(a+mid+1,a+r+1,cmp2);
59     int i=l,j=mid+1;
60     while(j<=r)
61     {
62         while(i<=mid&&a[i].b<a[j].b)
63             update(a[i].c,1),i++;
64         a[j].ans+=query(n)-query(a[j].c),j++;
65     }
66     for (int j=l;j<i;j++)
67         update(a[j].c,-1);
68         
69     sort(a+l,a+mid+1,cmp3);
70     sort(a+mid+1,a+r+1,cmp3);
71     i=l,j=mid+1;
72     while(j<=r)
73     {
74         while(i<=mid&&a[i].b>a[j].b)
75             update(a[i].c,1),i++;
76         a[j].ans+=query(a[j].c),j++;
77     }
78     for (int j=l;j<i;j++)
79         update(a[j].c,-1);
80 }
81 int main()
82 {
83     n=read(),m=read();
84     for (int i=1;i<=n;i++){int x=read();a[x].b=i;}
85     for (int i=1;i<=m;i++){int x=read();a[x].a=m-i+1;}//倒着表示什么时候插入 
86     for (int i=1;i<=n;i++)a[i].c=i;
87     sort(a+1,a+n+1,cmp1);
88     cdq(1,n);
89     for (int i=1;i<=n;i++)
90         ans[a[i].a]+=a[i].ans;
91     for (int i=1;i<=m;i++)
92         ans[i]+=ans[i-1];
93     for (int i=m;i>=1;i--)
94         printf("%lld\n",ans[i]);
95 }

 

posted @ 2017-12-05 08:10  Kaiser-  阅读(190)  评论(0编辑  收藏  举报