Codeforces Round #737 (Div. 2) D. Ezzat and Grid 线段树优化动态规划

题意

n n n行全0段,将其中 m m m段赋值为1,问满足条件的行数最多是多少。条件为:两行至少有一列全1。

分析

类似最长上升子序列从前向后转移。

每次当前行选出一个满足条件的最大行进行转移,上述找满足条件的值最大行的操作可以使用线段树优化。

由于数据范围在 1 e 9 1e^9 1e9之内,需要离散化。

需要一颗区间赋值,求区间最值的线段树,除值外线段树还需存当前值对应的行数,可以使用 p a i r pair pair进行存储。

按照行从小到大的顺序操作,先更新答案,再对当前区间赋值为当前答案最大值+1。

如果对于当前行的一段1来说,如果这段1对应的列数在之前为出现1,则仅看这段1,当前行答案为1。如果在之前出现过,则答案为 q u e r y _ m a x ( l , r ) + 1 query\_max(l,r)+1 query_max(l,r)+1

由于需要输出方案,使用 p r e pre pre数组记录路径。

时间复杂度 O ( n l o g n ) O(nlogn) O(nlogn)

代码

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
#define endl '\n'
ll gcd(ll a, ll b) { return b == 0 ? a : gcd(b, a % b); }
ll lcm(ll a, ll b) { return a / gcd(a, b) * b; }
void input() { freopen("in.txt", "r", stdin), freopen("out.txt", "w", stdout); }

const int N = 1e6 + 10, M = N * 2, inf = 1e8;

struct Node{
    int l, r;
    pii v, lazy;
}tr[N * 4];
pii Max(pii a, pii b){
    if(a.first > b.first) return a;
    return b;
}
void pushup(int u){
    tr[u].v = Max(tr[u<<1].v, tr[u<<1|1].v);
}
void pushdown(int u){
    if(tr[u].lazy.first != 0){
        tr[u<<1].lazy = tr[u<<1|1].lazy = tr[u].lazy;
        tr[u<<1].v = tr[u<<1|1].v = tr[u].lazy;
        tr[u].lazy = {0, 0};
    }
}
void build(int u, int l, int r){
    tr[u].l = l, tr[u].r = r;
    if(l == r) return;
    else{
        int mid = (l + r) >> 1;
        build(u << 1, l, mid);
        build(u << 1 | 1, mid + 1, r);
        pushup(u);
    }
}
void update(int u, int l, int r, pii v){
    if(l <= tr[u].l && tr[u].r <= r){
        tr[u].v = v;
        tr[u].lazy = v;
    }else{
        pushdown(u);
        int mid = (tr[u].l + tr[u].r) >> 1;
        if(l <= mid) update(u <<1, l, r, v);
        if(r > mid) update(u<<1|1, l, r, v);
        pushup(u);
    }
}
pii query(int u, int l, int r){
    if(l <= tr[u].l && tr[u].r <= r){
        return tr[u].v;
    }else{
        pushdown(u);
        int mid = (tr[u].l + tr[u].r) >> 1;
        pii res = {0, 0};
        if(l <= mid) res = Max(res, query(u<<1, l, r));
        if(r > mid) res = Max(res, query(u<<1|1, l, r));
        return res;
    }
}
int cnt, b[N], n, m, pre[N], vis[N];
vector<pii> G[N];
struct Q{
    int id, l, r;
}q[N];
int main() {
    ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
    cin>>n>>m;
    for(int i = 1; i <= m; i++){
        cin>>q[i].id>>q[i].l>>q[i].r;
        b[++cnt] = q[i].l, b[++cnt] = q[i].r;
    }
    sort(b + 1, b + cnt + 1);
    cnt = unique(b + 1, b + cnt + 1) - b - 1;
    for(int i = 1; i <= m; i++){
        q[i].l = lower_bound(b + 1, b + cnt + 1, q[i].l) - b;
        q[i].r = lower_bound(b + 1, b + cnt + 1, q[i].r) - b;
        G[q[i].id].push_back({q[i].l, q[i].r});
    }
    build(1, 1, cnt);
    int flag = 0, ans = 0;
    for(int i = 1; i <= n; i++){
        int now = -1;
        for(auto it : G[i]){
            pii t = query(1, it.first, it.second);
            if(t.first > now){
                now = t.first;
                pre[i] = t.second;
            }
        }
        if(now + 1 > ans){
            ans = now + 1;
            flag = i;
        }
        for(auto it : G[i]){
            update(1, it.first, it.second, {now + 1, i});
        }
    }
    cout<<n-ans<<endl;
    for(;flag != 0; flag = pre[flag]) vis[flag] = 1;
    for(int i = 1; i <= n; i++) if(vis[i] == 0) cout<<i<<" ";
    return 0;
}
  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值