12
12
2015
0

3295: [Cqoi2011]动态逆序对

3295: [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

 

 

 

CDQ分治

 

先预处理出 逆序对总数ans 和 每个元素所在的逆序对数fi

每删除元素i,逆序对总数ans -= fi

但是由于一个逆序对有两个元素决定,所以可能会出现重复删的情况

我们二分求元素i是某逆序对中后删的元素的情况数

我们用a,b,c 分别表示元素的删除时间,元素大小,元素位置

 

元素a是某个逆序对后删的元素

当且仅当有b满足 b.a < a.a 且 b.b < a.b 且 b.c > a.c

         或b.a < a.a 且 b.b > a.b 且 b.c < a.c

 

所以求元素i是某逆序对中后删的元素的情况数

即为求满足 k.a < i.a 且 k.b < i.b 且 k.c > i.c

      或k.a < i.a 且 k.b > i.b 且 k.c < i.c 的k的个数

 

这样这道题就和 BZOJ3262 一样了

 

#include <cstdio>
#include <algorithm>
using namespace std;
const int MaxN = 100010;
const int MaxM = 50010;
int N, M;
long long Ans;
int delta[MaxN];
int a[MaxN], f[MaxN];
struct point{
	int a, b, c, key;
	inline point(int x = 0, int y = 0, int z = 0, int k = 0){
		a = x, b = y, c = z, k = key;
	}
}p[MaxM], q[MaxM];
inline int lowbit(int x){
	return x & -x;
}
inline void ins(int x){
	for (; x <= N; x += lowbit(x))
	    ++delta[x];
}
inline int query(int x){
	int res = 0;
	for (; x; x -= lowbit(x))
	    res += delta[x];
	return res; 
}
inline void New(int x){
	for (; x <= N; x += lowbit(x))
	    if (delta[x]) delta[x] = 0;
	    else break;
}
inline void solve1(int l, int r){
	if (l == r) return;
	int mid = l + r >> 1;
	solve1(l, mid), solve1(mid + 1, r);
	int t1 = l, t2 = mid + 1;
	for (int i = l; i <= r; ++i)
	    if (t1<= mid && p[t1].b < p[t2].b || t2 > r) {
	    	q[i] = p[t1++];
	    	ins(q[i].c);
		}
		else {
			q[i] = p[t2++];
			int res =  t1 - l - query(q[i].c);
			q[i].key += res; 
		}
	for (int i = l; i <= r; ++i)
	    p[i] = q[i], New(p[i].c);
}
inline void solve2(int l, int r){
	if (l == r) return;
	int mid = l + r >> 1;
	solve2(l, mid), solve2(mid + 1, r);
	int t1 = l, t2 = mid + 1;
	for (int i = l; i <= r; ++i)
	    if (t1<= mid && p[t1].b > p[t2].b || t2 > r) {
	    	q[i] = p[t1++];
	    	ins(q[i].c);
		}
		else {
			q[i] = p[t2++];
			int res =  query(q[i].c);
			q[i].key += res; 
		}
	for (int i = l; i <= r; ++i)
	    p[i] = q[i], New(p[i].c);
}
inline bool cmp(const point &a, const point &b){
	return a.a < b.a;
}
inline int Get(){
	char Ch;
	while ((Ch = getchar()) < '0' || Ch > '9');
	int Num = Ch - '0';
	while ((Ch = getchar()) >= '0' && Ch <='9')
	    Num = Num * 10 + Ch - '0';
	return Num;
}
int main(){
	N = Get(); M = Get(); 
	for (int i = 1; i <= N; ++i){
		int x = Get();
	    a[x] = i;
	}
	for (int i = 1; i <= M; ++i){
		int x = Get();
		p[i] = point(i, x, a[x], 0);
	}
	for (int i = 1; i <= N; ++i){
		ins(a[i]);
		int res = i - query(a[i]);
		Ans += (f[i] = res);
	}
	for (int i = 1; i <= N; ++i) delta[i] = 0;
	for (int i = N; i; --i){
		int res = query(a[i]);
	    f[i] += res;
		ins(a[i]); 
	}
	for (int i = 1; i <= N; ++i) delta[i] = 0;
	solve1(1, M);
    sort(p + 1, p + M + 1,cmp);
	solve2(1, M);
    sort(p + 1, p + M + 1,cmp);
    for (int i = 1; i <= M; ++i){
    	printf("%lld\n", Ans);
    	Ans = Ans - f[p[i].b] + p[i].key;
	}
} 

Ps:答案要开longlong

Category: BZOJ | Tags: 分治 bit bzoj | Read Count: 328

登录 *


loading captcha image...
(输入验证码)
or Ctrl+Enter

Host by is-Programmer.com | Power by Chito 1.3.3 beta | Theme: Aeros 2.0 by TheBuckmaker.com