题解:CF2239C Revival

这很神秘你知道吗。难点在于想到倒着做。

显然

\[s_i-s_{i-1}=\sum_{j=1}^{i-1}[p_j>p_i] \]

也就是说,\(s_i-s_{i-1}\) 传达的信息是 \(p_i\)\(p_{1\sim i}\) 中的排名。

容易想到逐个确定 \(s_i\) 对应位置的值。

如果从左到右做,我们只知道 \(p_{1\sim i-1}\) 对应的值;但是如果从右到左做,确定了 \(p_{i+1\sim n}\) 的值后,\(p_{1\sim i}\) 的值构成的集合就可以确定了。

于是考虑从右到左做。设当前一对相邻的位置为 \(s_l\)\(s_r\)\(p_{l+1\sim r-1}\)\(p_{r+1\sim n}\) 中的值都已经确定了,此时可以确定 \(p_{1\sim r}\) 中值构成的集合 \(S\)。分离贡献:

\[\begin{align*} s_r-s_l&=\sum_{i=l+1}^{r-1}\sum_{j=i+1}^{r-1}[p_i>p_j]+\sum_{i=l+1}^{r-1}\sum_{x\in S}[x>p_i]-\frac{(r-l-1)(r-l-2)}{2}\\ &+\sum_{x\in S}[x>p_r]-\sum_{i=l+1}^{r-1}[p_i<p_r] \end{align*} \]

\(p_r\) 无关的部分是定值 \(C\)。设

\[f(v)=\sum_{x\in S}[x>v]-\sum_{i=l+1}^{r-1}[p_i<v] \]

不妨限制定义域为 \(S\),则任取 \(v_1,v_2\in S\ (v_1<v_2)\) 做差:

\[f(v_1)-f(v_2)=\sum_{x\in S}[v_1<x\leq v_2]+\sum_{i=l+1}^{r-1}[v_1\leq p_i<v_2] \]

显然上式 \(>0\),因此 \(f\)\(S\) 上严格单调递减。类似地,不难得出 \(f\)\([n]\) 上单调不增。由于题目保证有解,我们二分出最小的 \(x\) 使得 \(f(x)\leq s_r-s_l-C\),取 \(p_r=x\) 即可。

开两棵树状数组分别维护 \(p_{l+1\sim r-1}\)\(S\) 即可。时间复杂度为 \(\mathcal{O}(n\log^2{n})\)

代码
#include <bits/stdc++.h>

using namespace std;

using ll = long long;
using i128 = __int128;
using ui = unsigned int;
using ull = unsigned long long;
using u128 = unsigned __int128;
using ld = long double;
using pii = pair<int, int>;
const int MAXN = 2e5 + 5;

template<typename T> T lowbit(T x) { return x & -x; }
template<typename T> void chkMin(T &x, T y) { x = y < x ? y : x; }
template<typename T> void chkMax(T &x, T y) { x = x < y ? y : x; }
constexpr int lg2(ll x) { return 63 ^ __builtin_clzll(x); }
constexpr ll bitCeil(ll x) { return x == 1 ? 1ll : 1ll << lg2(x - 1) + 1; }

int tc, n;
ll a[MAXN];
bool tp[MAXN];

struct BIT {
	int c[MAXN];
	void init(int n) {
		fill(c + 1, c + n + 1, 0);
	}
	int query(int x) {
		int res = 0;
		for (; x; x -= lowbit(x)) res += c[x];
		return res;
	}
	void add(int x, int v) {
		for (; x <= n; x += lowbit(x)) c[x] += v;
	}
} ft1, ft2;

int main() {
	ios::sync_with_stdio(false);
	cin.tie(nullptr);
	cin >> tc;
	while (tc--) {
		cin >> n;
		for (int i = 1; i <= n; ++i) {
			string s;
			cin >> s >> a[i];
			tp[i] = s[0] == 's';
		}
		vector<int> pos;
		for (int i = n; i; --i)
			if (tp[i])
				pos.emplace_back(i);
		pos.emplace_back(0);
		ft1.init(n);
		ft2.init(n);
		for (int i = 1; i <= n; ++i) ft1.add(i, 1);
		for (int i = n; i > pos[0]; --i) ft1.add(a[i], -1);
		for (int i = 0; i < pos.size() - 1; ++i) {
			int l = pos[i + 1], r = pos[i];
			ll val = 0;
			for (int j = r - 1; j >= l + 1; --j) {
				val += ft2.query(a[j] - 1);
				ft2.add(a[j], 1);
			}
			for (int j = l + 1; j <= r - 1; ++j) val += ft1.query(n) - ft1.query(a[j]);
			val -= (ll)(r - l - 1) * (r - l - 2) >> 1;
			val = a[r] - a[l] - val;
			int L = 1, R = n;
			while (L < R) {
				int mid = L + R >> 1;
				ll v = ft1.query(n) - ft1.query(mid) - ft2.query(mid - 1);
				if (v <= val) R = mid;
				else L = mid + 1;
			}
			a[r] = L;
			ft1.add(a[r], -1);
			for (int j = l + 1; j <= r - 1; ++j) {
				ft1.add(a[j], -1);
				ft2.add(a[j], -1);
			}
		}
		for (int i = 1; i <= n; ++i) cout << a[i] << " \n"[i == n];
	}
	return 0;
}
posted @ 2026-06-28 12:00  P2441M  阅读(34)  评论(0)    收藏  举报