背包问题 [二维偏序, 树状数组]

mac2026-06-18  3

背 包 问 题 背包问题


正 解 部 分 \color{red}{正解部分}

二维偏序问题,

将所 有点 按照 v v v 为第一关键字, w w w 为第二关键字 从大到小 排序,

从前往后扫, 离散化坐标, 使用 树状数组 维护 y y y 的 前缀最大值, 记为 m a x _ c u r max\_cur max_cur

对于背包的限制, 将背包按容量 从大到小 排序, 维护一个指针从左往右根据物品的容量往右移动, 记为 t t t,

背包从容量大的开始选显然是最优的 .

min ⁡ ( t , m a x _ c u r ) \min(t, max\_cur) min(t,max_cur) 更新 .


实 现 部 分 \color{red}{实现部分}

#include<bits/stdc++.h> #define reg register int read(){ char c; int s = 0, flag = 1; while((c=getchar()) && !isdigit(c)) if(c == '-'){ flag = -1, c = getchar(); break ; } while(isdigit(c)) s = s*10 + c-'0', c = getchar(); return s * flag; } const int maxn = 1e5 + 5; int N; int M; int Len_2; int rl[maxn]; int B2[maxn]; struct Node{ int w, v; } A[maxn]; bool cmp(Node a, Node b){ return a.w==b.w?a.v>b.v:a.w>b.w; } struct Bit_Tree{ int v[maxn], lim; void Add(int k, int x){ while(k<=lim)v[k]=std::max(v[k], x), k+=k&-k; } int Query(int k){ int s = 0; while(k){ s = std::max(v[k], s); k -= k&-k; } return s; } } bit_t; void Work(){ N = read(); for(reg int i = 1; i <= N; i ++) A[i].w = read(), B2[i] = A[i].v = read(); std::sort(A+1, A+N+1, cmp); std::sort(B2+1, B2+N+1), Len_2 = std::unique(B2+1, B2+N+1) - B2-1; for(reg int i = 1; i <= N; i ++) A[i].v = std::lower_bound(B2+1, B2+Len_2+1, A[i].v)-B2; M = read(); for(reg int i = 1; i <= M; i ++) rl[i] = read(); std::sort(rl+1, rl+M+1, std::greater<int>()); int t = 0, Ans = 0; bit_t.lim = Len_2; memset(bit_t.v, 0, sizeof bit_t.v); for(reg int i = 1; i <= N; i ++){ while(t < M && rl[t+1] >= A[i].w) t ++; int p = bit_t.Query(Len_2-A[i].v+1), cur = std::min(t, p+1); bit_t.Add(Len_2-A[i].v+1, cur); Ans = std::max(Ans, cur); } printf("%d\n", Ans); } int main(){ int T = read(); while(T --) Work(); return 0; }
最新回复(0)