bzoj3295 [Cqoi2011]动态逆序对 cdq+树状数组
【bzoj3295】[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
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)。
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 }