bzoj3295 [Cqoi2011]动态逆序对
3295: [Cqoi2011]动态逆序对
Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 6119 Solved: 2142
[Submit][Status][Discuss]
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
分析:cdq分治比较裸的题目.考虑i,j如何才能构成逆序对:Ti < Tj,Xi < Xj,Yi > Yj.其中T是cdq分治中的时间,X是下标,Y是大小.因为题目只涉及到删除操作,那么可以用一个很常用的方法:时间倒流来处理.每增加一个点,看T ≤ mid的点中有多少x比它大并且y比它小的点,和x比它小并且y比它大的点.因为每次不光是要计算原先被删除的点构成的逆序对,还要算序列中剩下的数的逆序对.那么一开始将序列初始化为空序列,对每一个元素分配一个T,代表插入的时间,其中没有被删除的点要先分配,这样就能做到统计答案不遗漏了.
#include <cstdio> #include <cstring> #include <iostream> #include <algorithm> using namespace std; typedef long long ll; const int maxn = 100010; int n,m,pos[maxn],T; ll ans[maxn],c[maxn],Ans; struct node { int id,x,y; }e[maxn],p[maxn]; bool cmp(node a,node b) { if (a.x == b.x && a.y == b.y) return a.id < b.id; if (a.x == b.x) return a.y < b.y; return a.x < b.x; } void add(int x,int v) { while (x <= n) { c[x] += v; x += x & (-x); } } ll query(int x) { ll res = 0; while (x) { res += c[x]; x -= x & (-x); } return res; } void solve(int l,int r) { if (l == r) return; int mid = (l + r) >> 1; for (int i = l; i <= r; i++) { if (e[i].id <= mid) add(e[i].y,1); else ans[e[i].id] += query(n) - query(e[i].y); } for (int i = l; i <= r; i++) if (e[i].id <= mid) add(e[i].y,-1); for (int i = r; i >= l; i--) { if (e[i].id <= mid) add(e[i].y,1); else ans[e[i].id] += query(e[i].y); } for (int i = r; i >= l; i--) if (e[i].id <= mid) add(e[i].y,-1); int L = l,R = mid + 1; for (int i = l; i <= r; i++) { if (e[i].id <= mid) p[L++] = e[i]; else p[R++] = e[i]; } for (int i = l; i <= r; i++) e[i] = p[i]; solve(l,mid); solve(mid + 1,r); } int main() { scanf("%d%d",&n,&m); T = n; for (int i = 1; i <= n; i++) { scanf("%d",&e[i].y); e[i].x = i; pos[e[i].y] = i; } for (int i = 1; i <= m; i++) { int k; scanf("%d",&k); e[pos[k]].id = T--; } for (int i = 1; i <= n; i++) if (!e[i].id) e[i].id = T--; sort(e + 1,e + 1 + n,cmp); solve(1,n); for (int i = 1; i <= n; i++) Ans += ans[i]; for (int i = n; i > n - m; i--) { printf("%lld\n",Ans); Ans -= ans[i]; } return 0; }