BZOJ3295 动态逆序对

【问题描述】

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

【输入格式】

输入第一行包含两个整数n和m,即初始元素的个数和删除的元素个数。
以下n行每行包含一个1到n之间的正整数,即初始排列。以下m行每行一个正整数,依次为每次删除的元素。

【输出格式】

输出包含m行,依次为删除每个元素之前,逆序对的个数。

【输入样例】

5 4
1
5
3
4
2 5 1
4
2

【输出样例】

5
2
2
1

【样例解释】

(1,5,3,4,2)(1,3,4,2)(3,4,2)(3,2)(3)。


【数据规模】
N<=100000 , M<=50000

正解:cdq分治

解题报告:这个题是让我们边修改边求逆序对,我们可以先离线处理,把删除改成插入,然后序列中所有的逆序对应该满足三个条件,我们用三个字母表示,t表示插入时间,x表示位置,y表示值,然后每一对逆序对应该是t【j】<t【i】,(x【j】<x【i】&& y【j】>y【i】) 或 (x【j】>x【i】 && y【j】<y【i】),然后就转化为经典的三维偏序,用cdq分治解决。

 1 #include <iostream>
 2 #include <iomanip>
 3 #include <cstdlib>
 4 #include <cstdio>
 5 #include <cmath>
 6 #include <algorithm>
 7 #include <string>
 8 #include <cstring>
 9 #define File(a) freopen(a".in","r",stdin),freopen(a".out","w",stdout)
10 #define RG register
11 #define ll long long
12 const int N = 105000;
13 
14 using namespace std;
15 
16 int gi(){
17     char ch=getchar();int x=0;
18     while(ch<'0' || ch>'9')ch=getchar();
19     while (ch>='0' && ch<='9') {x=x*10+ch-'0';ch=getchar();}
20     return x;
21 }
22 
23 struct date{
24     int x,s;
25 }d[N],a[N],b[N];
26 
27 int f[N],q[N],id[N],y[N],n,m,ans[N];
28 bool vis[N];
29 void update(int x,int s){while(x<=n){y[x]+=s;x+=x&(-x);}return;}
30 int query(int x){int s=0;while(x){s+=y[x];x-=x&(-x);}return s;}
31 
32 void cdq(int l,int r){
33     if (l>=r) return;
34     RG int i,j,k;
35     int mid=(l+r)>>1;
36     cdq(l,mid);
37     cdq(mid+1,r);
38     for (i=mid+1,j=l; i<=r; i++){
39         while(d[j].x<d[i].x && j<=mid) update(d[j].s,1),j++;
40         ans[d[i].x]+=query(n)-query(d[i].s);
41     }
42     for (i=l; i<j; i++) update(d[i].s,-1);
43     for (i=r,j=mid; i>mid; i--){
44         while(j>=l && d[j].x>d[i].x) update(d[j].s,1),j--;
45         ans[d[i].x]+=query(d[i].s);
46     }
47     for (i=mid; i>j; i--) update(d[i].s,-1);
48     int a1=0,b1=0;
49     for (i=l; i<=mid; i++) a[++a1]=d[i];
50     for (i=mid+1; i<=r; i++) b[++b1]=d[i];
51     i=1,j=1,k=l;
52     while(i<=a1 && j<=b1) if (a[i].x<b[j].x) d[k++]=a[i++];
53         else d[k++]=b[j++];
54     while(i<=a1) d[k++]=a[i++];
55     while(j<=b1) d[k++]=b[j++];
56     return;
57 }
58 
59 int main(){
60     File("3295");
61     n=gi(),m=gi();RG int i,t=1;
62     for (i=1; i<=n; i++) f[i]=gi(),id[f[i]]=i;
63     for (i=1; i<=m; i++) q[i]=gi(),vis[q[i]]=1;
64     for (i=1; i<=n; i++) if (!vis[f[i]]) d[t++]=(date){i,f[i]};
65     for (i=m; i>=1; i--) d[t++]=(date){id[q[i]],q[i]};
66     cdq(1,n);
67     ll sum=0;
68     for (i=1; i<=n; i++) sum+=ans[i];
69     for (i=1; i<=m; i++) printf("%lld\n",sum),sum-=ans[id[q[i]]];
70     return 0;
71 }

 

posted @ 2017-02-18 21:59  Cjk_2001  阅读(223)  评论(0编辑  收藏  举报