loj #2729. 「JOISC 2016 Day 1」俄罗斯套娃
loj #2729. 「JOISC 2016 Day 1」俄罗斯套娃
先丢个官方题解
官方题解讲得比较详细
这题的关键其实就是把最小路径覆盖转换为最长不上升子序列
然后我们就可以先把询问和原来的点离线一下在离散化
按照A从大到小排序,然后就转换为了求最长不下降子序列问题
直接树状数组维护前缀最大值即可
看代码很容易明白的
code:
#include<bits/stdc++.h>
#define N 1000005
#define lowbit(x) (x & -x)
using namespace std;
struct A{
int x, y, id;
}a[N];
int cmp(A x, A y){
if(x.x != y.x) return x.x > y.x;
if(x.y != y.y) return x.y < y.y;
return x.id < y.id;//注意这里一定要按照id排序,想想为啥
}
int tree[N];
void update(int x, int y){//树状数组维护前缀最大值
for(; x < N; x += lowbit(x)) tree[x] = max(tree[x], y);
}
int query(int x){
int ret = 0;
for(; x; x -= lowbit(x)) ret = max(ret, tree[x]);
return ret;
}
int n, q, b[N], ANS[N];
int main(){
scanf("%d%d", &n, &q);
for(int i = 1; i <= n; i ++) scanf("%d%d", &a[i].x, &a[i].y), b[i] = a[i].y;
for(int i = 1; i <= q; i ++) scanf("%d%d", &a[i + n].x, &a[i + n].y), b[i + n] = a[i + n].y, a[i + n].id = i;//把问题离线一下
sort(b + 1, b + 1 + n + q);//排序用于离散化
sort(a + 1, a + 1 + n + q, cmp);//把询问排序
for(int i = 1; i <= n + q; i ++){
int pos = lower_bound(b + 1, b + 1 + n + q, a[i].y) - b;//离散化
if(a[i].id) ANS[a[i].id] = query(pos);//求最长不下降子序列
else update(pos, query(pos) + 1);//如果是DAG上的点就加上去
}
for(int i = 1; i <= q; i ++) printf("%d\n", ANS[i]);//输出
return 0;
}
离线大法吼哇
坑点
就是多关键字排序那里一定要注意id也要参与排序,不然会贡献不充分