题目大意

给定一个长为 $n$ 的排列 $p$,有如下操作

  • 交换 $p_{x}, p_{x+1}$。
  • 询问排列经过 $k$ 轮冒泡排序后的逆序数。

分析

难点在观察冒泡排序对逆序数的影响,考虑一个数 $p_i$ 受其前面的数影响:

  • 如果 $p_i$ 前面没有比 $p_i$ 大的,冒泡后 $p_{i’}$ 仍不贡献逆序数。
  • 如果 $p_i$ 前面有 $j$ 个比当前数大的,冒泡后有且仅有一个数穿过了 $p_{i’}$,贡献的逆序数减 $1$。

故第 $k$ 轮冒泡后,即每个数贡献的逆序数都要减 $k$。又因为不应减到负数,因此需要用两个树状数组维护。

#include "template/ds/fwtree/1.hpp"

int main() {
	int n = rr(), m = rr();
	vector<int> p(n);
	for (int i = 0; i < n; i++)
		p[i] = rr();

	vector<ll> inver(n);
	{
		vector<pii> tp(n);
		for (int i = 0; i < n; i++)
			tp[i] = {p[i], i + 1};
		sort(tp.begin(), tp.end());
		fwtree_1<ll> tr(n + 1);
		for (auto [x, i] : tp) {
			inver[i - 1] = i - 1 - tr.sum(1, i);
			tr.add(i, 1);
		}
	}
	fwtree_1<ll> tr1(n + 1), tr2(n + 1);
	for (auto ii : inver) {
		tr1.add(ii, 1), tr2.add(ii, ii);
	}
	
	while (m--) {
		int op = rr();
		if (op == 1) {
			int x = rr() - 1;
			swap(p[x], p[x + 1]);
			swap(inver[x], inver[x + 1]);
			if (p[x] < p[x + 1]) {
				auto &ii = inver[x];
				tr1.add(ii, -1);
				tr2.add(ii, -ii);
				ii--;
				tr1.add(ii, 1);
				tr2.add(ii, ii);
			} else {
				auto &ii = inver[x + 1];
				tr1.add(ii, -1);
				tr2.add(ii, -ii);
				ii++;
				tr1.add(ii, 1);
				tr2.add(ii, ii);
			}
		} else {
			ll k = rr();
			if (k > n) {
				printf("0\n");
			} else {
				ll ans = tr2.sum(k, n);
				ans -= tr1.sum(k, n) * k;
				printf("%lld\n", ans);
			}
		}
	}
	return 0;
}