学了一下,感觉海星。
说是整体二分,不如就说是分治。
考虑这个问题:Luogu P3834 【模板】可持久化线段树 2
次询问,每次询问给出 ,问 中第 小的值。
一个显然的结论:答案满足单调性,可以二分。
我们首先先简化一下:如果 ,怎么维护?
先二分出一个 ,建立树状数组维护 的个数,判断其是否小于 即可。
那加入 次询问怎么办呢?
可以离线下来,运用分治思想将同一范围内的答案统一处理。
具体的,我们定义结构体 。对于询问, 表示查询 的第 小,此时的 ,对于原数, 表示原值。
定义操作函数 solve(l,r,L,R)
表示当前处理到 ,值域为 ,对于 ,显然, 的答案就为 ()。
码风有点抽象,切勿锐评 /qd。
当然你想要正常一点的也可以私信我。
点击查看代码
using namespace std;
const int N = 2e5 + 100;
int n, m, cnt, mn = 1e18, mx = -1e18, ans[N];
struct Node {
int x, y, k, id, opt;
} q[N], q1[N], q2[N];
struct Bit {
int f[N];
int lowbit(int x) { return x & -x; }
void add(int x, int k) { while (x <= n) { f[x] += k; x += lowbit(x); } }
int getsum(int x) { int sum = 0; while (x) { sum += f[x]; x -= lowbit(x); } return sum; }
} bit;
void solve(int l, int r, int L, int R) {
if (l > r) return ;
if (L == R) { for (int i = l; i <= r; i++) { if (q[i].opt) { ans[q[i].id] = L; } } return ; }
int mid = (L + R) >> 1, p1 = 0, p2 = 0;
for (int i = l; i <= r; i++) { if (!q[i].opt) { if (q[i].x <= mid) { bit.add(q[i].id, 1); q1[++p1] = q[i]; } else { q2[++p2] = q[i]; } } else { int num = bit.getsum(q[i].y) - bit.getsum(q[i].x - 1); if (num >= q[i].k) { q1[++p1] = q[i]; } else { q[i].k -= num; q2[++p2] = q[i]; } } }
for (int i = 1; i <= p1; i++) { if (!q1[i].opt) { bit.add(q1[i].id, -1); } }
for (int i = 1; i <= p1; i++) { q[i + l - 1] = q1[i]; }
for (int i = 1; i <= p2; i++) { q[i + l + p1 - 1] = q2[i]; }
solve(l, l + p1 - 1, L, mid), solve(l + p1, r, mid + 1, R);
}
signed main() {
cin >> n >> m;
for (int i = 1, x; i <= n; i++) { cin >> x; q[++cnt] = {x, 0, 0, i, 0}; mn = min(mn, x), mx = max(mx, x); }
for (int i = 1, l, r, k; i <= m; i++) { cin >> l >> r >> k; q[++cnt] = {l, r, k, i, 1}; }
solve(1, cnt, mn, mx);
for (int i = 1; i <= m; i++) cout << ans[i] << '\n';
return 0;
}
Luogu P2617 Dynamic Rankings
纪念调了一个小时。
和上一题一样,但是要离散化。对于修改记录一下在树状数组上修改相应的值即可。
但是,要注意,这题按上一题的写法不行,因为上一题我的代码中原数记录的是 的 ,而询问记录的是 的 ,而这题要离散化,所以要统一成为 。
因为这个调了一个小时。
这题的代码和上题差不多。所以你可以提取上一题正常码风的代码。
点击查看代码
using namespace std;
const int N = 2e5 + 100;
int n, m, cnt, ans[N], a[N], b[N], tot, in[N];
struct Node {
int opt, k, x, y, id;
} q[N], q1[N], q2[N];
struct Bit {
int f[N];
int lowbit(int x) {
return x & -x;
}
void add(int x, int k) {
while (x <= n) {
f[x] += k;
x += lowbit(x);
}
}
int getsum(int x) {
int sum = 0;
while (x) {
sum += f[x];
x -= lowbit(x);
}
return sum;
}
} bit;
void solve(int l, int r, int L, int R) {
if (l > r) return ;
if (L == R) {
for (int i = l; i <= r; i++) {
if (!q[i].opt) {
ans[q[i].id] = L;
}
}
return ;
}
int mid = (L + R) >> 1, p1 = 0, p2 = 0;
for (int i = l; i <= r; i++) {
if (q[i].opt) {
if (q[i].k <= mid) {
bit.add(q[i].id, q[i].opt);
q1[++p1] = q[i];
} else {
q2[++p2] = q[i];
}
} else {
int num = bit.getsum(q[i].y) - bit.getsum(q[i].x - 1);
if (num >= q[i].k) {
q1[++p1] = q[i];
} else {
q[i].k -= num;
q2[++p2] = q[i];
}
}
}
for (int i = 1; i <= p1; i++) {
if (q1[i].opt) {
bit.add(q1[i].id, -q1[i].opt);
}
}
for (int i = 1; i <= p1; i++) {
q[i + l - 1] = q1[i];
}
for (int i = 1; i <= p2; i++) {
q[i + l + p1 - 1] = q2[i];
}
solve(l, l + p1 - 1, L, mid);
solve(l + p1, r, mid + 1, R);
}
int main() {
cin >> n >> m;
for (int i = 1; i <= n; i++) {
cin >> a[i];
b[++tot] = a[i];
q[++cnt] = {1, a[i], 0, 0, i};
}
for (int i = 1; i <= m; i++) {
char c;
cin >> c;
if (c == 'Q') {
int l, r, k;
cin >> l >> r >> k;
q[++cnt] = {0, k, l, r, i};
} else {
int l, r;
cin >> l >> r;
q[++cnt] = {-1, a[l], 0, 0, l};
q[++cnt] = {1, r, 0, 0, l};
b[++tot] = r;
a[l] = r;
}
}
sort(b + 1, b + tot + 1);
tot = unique(b + 1, b + tot + 1) - b - 1;
for (int i = 1; i <= cnt; i++) {
if (!q[i].opt) {
continue;
}
int h = lower_bound(b + 1, b + tot + 1, q[i].k) - b;
in[h] = q[i].k;
q[i].k = h;
}
solve(1, cnt, 1, tot);
for (int i = 1; i <= m; i++) {
// cout << ans[i] << ' ';
if (ans[i]) {
cout << in[ans[i]] << '\n';
}
}
return 0;
}
Luogu P3527 [POI2011] MET-Meteors
这道题不需要离散化,但是要注意区间总长度为 ,然后树状数组维护即可。
点击查看代码
using namespace std;
const int N = 8e6 + 100;
int n, m, cnt, ans[N], t;
struct Node {
int x, y, k, id;
} q[N];
struct Edge {
int val, id;
} g[N], q1[N], q2[N];
vector<int> G[N];
struct Bit {
int f[N];
int lowbit(int x) {
return x & -x;
}
void add(int x, int k) {
while (x <= 2 * m) {
f[x] += k;
x += lowbit(x);
}
}
int getsum(int x) {
int sum = 0;
while (x) {
sum += f[x];
x -= lowbit(x);
}
return sum;
}
} bit;
int query(int x) {
int ans = 0;
for (int i = 0; i < G[g[x].id].size(); i++) {
ans += bit.getsum(G[g[x].id][i]) + bit.getsum(G[g[x].id][i] + m);
if (ans >= g[x].val) {
return ans;
}
}
return ans;
}
void solve(int l, int r, int L, int R) {
if (l > r) {
return ;
}
if (L == R) {
for (int i = l; i <= r; i++) {
ans[g[i].id] = L;
}
return ;
}
int mid = (L + R) >> 1, p1 = 0, p2 = 0;
for (int i = L; i <= mid; i++) {
bit.add(q[i].x, q[i].k);
bit.add(q[i].y + 1, -q[i].k);
}
for (int i = l; i <= r; i++) {
int num = query(i);
if (num >= g[i].val) {
q1[++p1] = g[i];
} else {
g[i].val -= num;
q2[++p2] = g[i];
}
}
for (int i = L; i <= mid; i++) {
bit.add(q[i].x, -q[i].k);
bit.add(q[i].y + 1, q[i].k);
}
for (int i = 1; i <= p1; i++) {
g[i + l - 1] = q1[i];
}
for (int i = 1; i <= p2; i++) {
g[i + l + p1 - 1] = q2[i];
}
solve(l, l + p1 - 1, L, mid);
solve(l + p1, r, mid + 1, R);
}
signed main() {
cin >> n >> m;
for (int i = 1, x; i <= m; i++) {
cin >> x;
G[x].push_back(i);
}
for (int i = 1, x; i <= n; i++) {
cin >> x;
g[i] = {x, i};
}
cin >> t;
for (int i = 1, l, r, k; i <= t; i++) {
cin >> l >> r >> k;
q[i] = {l, r, k, i};
if (r < l) {
q[i].y += m;
}
}
t++;
q[t] = {1, 2 * m, (int)1e9, t};
solve(1, n, 1, t);
for (int i = 1; i <= n; i++) {
// cout << ans[i] << ' ';
if (ans[i] == t) {
cout << "NIE\n";
} else {
cout << ans[i] << '\n';
}
}
return 0;
}
__EOF__
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探
· 为什么 退出登录 或 修改密码 无法使 token 失效