背包问题 [二维偏序, 树状数组]
二维偏序问题,
将所 有点 按照 为第一关键字, 为第二关键字 从大到小 排序,
从前往后扫, 离散化坐标, 使用 树状数组 维护 的 前缀最大值, 记为
对于背包的限制, 将背包按容量 从大到小 排序, 维护一个指针从左往右根据物品的容量往右移动, 记为 ,
背包从容量大的开始选显然是最优的 .
用 更新 .
#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;
}