[ARC181D] Prefix Bubble Sort 题解

朴素的方法当然就是直接模拟,复杂度貌似是 \(O(n^2 \log n)\),倒闭。
尝试优化无果。

我们不妨换个角度考虑:我们进行一轮 prefix 冒泡排序后,了哪些逆序对?
进行冒泡排序时,我们相当于移动了 prefix max,剩下的元素集体向前 slide 一格,并与前面的 prefix max 拆散原有的逆序对,即产生 \(-1\) 的贡献。
注意到操作序列有序。
我们枚举所有元素 \(i\),查看前面大于自身的元素个数 \(s\),再 lower_bound 出第一次影响到 \(i\) 的操作编号 \(p\),那么这个非 prefix max 元素就会在操作 \([p, p+s-1]\) 均产生 \(-1\) 的贡献。差分算一下即可。
要算逆序对等等的,树状数组搞一下。

总时间复杂度 \(O(n \log n)\)

#include <bits/stdc++.h>
#define inf 0x3f3f3f3f
#define Linf 0x3f3f3f3f3f3f3f3f
#define pii pair<int, int> 
#define all(v) v.begin(), v.end()
using namespace std;

//#define filename "xxx" 
#define FileOperations() freopen(filename".in", "r", stdin), freopen(filename".out", "w", stdout)
//#define multi_cases 1

namespace Traveller {
	const int N = 2e5+2;
	
	int n, a[N];
	int m, b[N];
	
	int lowbit(int x) { return x & -x; }
	struct BIT {
		int n, c[N];
		void init(int n = 0) {
			this->n = n;
			memset(c, 0, sizeof(int) * (n+1));
		}
		void add(int idx, int v) { for(; idx <= n; idx += lowbit(idx)) c[idx] += v; }
		int query(int idx) {
			int res = 0;
			for(; idx; idx -= lowbit(idx)) res += c[idx];
			return res;
		}
		int query(int l, int r) { return query(r) - query(l-1); }
	} tr;
	
	int diff[N << 1];
	
	void main() {
		cin >> n;
		for(int i = 1; i <= n; ++i) scanf("%d", &a[i]);
		cin >> m;
		for(int i = 1; i <= m; ++i) scanf("%d", &b[i]);
		
		long long ans = 0;
		tr.init(n);
		for(int i = 1; i <= n; ++i) {
			ans += tr.query(a[i], n);
			tr.add(a[i], 1);
		}
		
		tr.init(n);
		for(int i = 1; i <= n; ++i) {
			int p = lower_bound(b+1, b+m+1, i) - b;
			int s = tr.query(a[i], n);
			++diff[p], --diff[p + s];
			tr.add(a[i], 1);
		}
		for(int i = 1; i <= m; ++i) diff[i] += diff[i-1];
		for(int i = 1; i <= m; ++i) {
			ans -= diff[i];
			printf("%lld\n", ans);
		}
	}
}

signed main() {
#ifdef filename
	FileOperations();
#endif
	
	signed _ = 1;
#ifdef multi_cases
	scanf("%d", &_);
#endif
	while(_--) Traveller::main();
	return 0;
}


posted @ 2025-01-17 19:55  Water_M  阅读(12)  评论(0)    收藏  举报