CodeForces 1540D Inverse Inversions

洛谷传送门

CF 传送门

小清新题。

首先容易发现每个合法的 b 唯一对应一个排列,大概就是每个时刻排列元素的相对顺序,然后插入到相应的位置。

但是这样太麻烦了。发现题目只要求求单点的 p 值。这应该有更简单的方法。

考虑令 biibi 表示 pi 在前缀 [1,i] 的排名。那么我们时刻维护 pi,然后遍历 i+1n,若 bip 那么令 pp+1。这样我们得到了一个 O(nq) 的做法。

一种优化方向是分块。预处理出每个块每个数经过后会变成什么。设 x 经过后变成 fx。容易发现 f 的值域为 [1,len],也就是说它是一个 1len 的分段函数。那么求出每一段的断点就可以二分求出一个数经过这个块后会增加多少。

考虑如何对一个块预处理 fx。相当于每次找到第一个 ai+ik 的位置 i,然后对 [i,n]1。容易树状数组维护,找到第一个位置可以树状数组上二分。

这样全部找到的位置就是分段函数的断点。

时间复杂度 O(nnlogn)

code
// Problem: D. Inverse Inversions
// Contest: Codeforces - Codeforces Round 728 (Div. 1)
// URL: https://codeforces.com/problemset/problem/1540/D
// Memory Limit: 512 MB
// Time Limit: 5000 ms
//
// Powered by CP Editor (https://cpeditor.org)
#include <bits/stdc++.h>
#define pb emplace_back
#define fst first
#define scd second
#define mkp make_pair
#define mems(a, x) memset((a), (x), sizeof(a))
using namespace std;
typedef long long ll;
typedef double db;
typedef unsigned long long ull;
typedef long double ldb;
typedef pair<ll, ll> pii;
const int maxn = 100100;
int n, m, a[maxn], blo, bel[maxn], L[maxn], R[maxn], f[330][330];
struct BIT {
int c[maxn];
inline void update(int x, int d) {
for (int i = x; i <= n; i += (i & (-i))) {
c[i] += d;
}
}
inline int find(int x) {
int p = 0, s = 0;
for (int i = 16; ~i; --i) {
if (p + (1 << i) <= n && s + c[p + (1 << i)] < x) {
s += c[p += (1 << i)];
}
}
return p + 1;
}
} B;
inline void build(int x) {
for (int i = L[x]; i <= R[x]; ++i) {
int p = B.find(a[i]);
B.update(p, 1);
f[x][i - L[x] + 1] = p;
}
sort(f[x] + 1, f[x] + R[x] - L[x] + 2);
for (int i = 1; i <= R[x] - L[x] + 1; ++i) {
B.update(f[x][i], -1);
}
}
void solve() {
scanf("%d", &n);
blo = sqrt(n);
for (int i = 1; i <= n; ++i) {
scanf("%d", &a[i]);
B.update(i, 1);
a[i] = i - a[i];
bel[i] = (i - 1) / blo + 1;
if (!L[bel[i]]) {
L[bel[i]] = i;
}
R[bel[i]] = i;
}
for (int i = 1; i <= bel[n]; ++i) {
build(i);
}
scanf("%d", &m);
while (m--) {
int op, x, y;
scanf("%d%d", &op, &x);
if (op == 1) {
scanf("%d", &y);
a[x] = x - y;
build(bel[x]);
} else {
int p = a[x];
for (int i = x + 1; i <= R[bel[x]]; ++i) {
p += (a[i] <= p);
}
for (int i = bel[x] + 1; i <= bel[n]; ++i) {
int t = upper_bound(f[i] + 1, f[i] + R[i] - L[i] + 2, p) - f[i] - 1;
p += t;
}
printf("%d\n", p);
}
}
}
int main() {
int T = 1;
// scanf("%d", &T);
while (T--) {
solve();
}
return 0;
}
posted @   zltzlt  阅读(10)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 【杂谈】分布式事务——高大上的无用知识?
点击右上角即可分享
微信分享提示