bzoj3295 [Cqoi2011]动态逆序对
2018-01-06 12:21
429 查看
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 41
5
3
4
2
5
1
4
2
Sample Output
52
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; }
相关文章推荐
- 【BZOJ】3295: [Cqoi2011]动态逆序对
- bzoj3295 [Cqoi2011]动态逆序对
- 【CDQ分治】BZOJ3295 [Cqoi2011]动态逆序对
- [BZOJ3295] [Cqoi2011]动态逆序对 && CDQ分治
- BZOJ 3295: [Cqoi2011]动态逆序对
- BZOJ 3295 【CQOI2011】 动态逆序对
- [BZOJ3295][CQOI2011]动态逆序对
- bzoj 3295: [Cqoi2011]动态逆序对
- 【CQOI2011】【BZOJ3295】动态逆序对
- BZOJ 3295 [Cqoi2011] 动态逆序对 CDQ分治题解
- 【BZOJ】3295: [Cqoi2011]动态逆序对
- [BZOJ 3295] CQOI 2011 动态逆序对 · 分块 & 逆序对
- bzoj3295: [Cqoi2011]动态逆序对
- bzoj3295 [Cqoi2011]动态逆序对
- bzoj 3295: [Cqoi2011]动态逆序对 【cdq分治】
- 【Cqoi2011】【BZOJ3295】动态逆序对
- 【CQOI2011】bzoj3295 动态逆序对【解法二】
- bzoj3295: [Cqoi2011]动态逆序对
- 【树状数组+线段树动态开点】BZOJ3295(Cqoi2011)[动态逆序对]题解
- BZOJ 3295 [Cqoi2011]动态逆序对 树状数组套线段树