Codeforces Round #737 (Div. 2) D. Ezzat and Grid 线段树模拟最长上升子序列

Posted kaka0010

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Codeforces Round #737 (Div. 2) D. Ezzat and Grid 线段树模拟最长上升子序列相关的知识,希望对你有一定的参考价值。

原题链接:https://codeforces.ml/contest/1557/problem/D

题意

有n行长度为1e9的01串,如果两个串相同位置都有1,我们称这两个串是美丽串,可以删除一些串,问最长美丽串的长度是多少。

分析

题意还是比较明显的,最长子串我们可以转化成最长上升子序列的模型。在动态规划中LIS就可以用线段树优化到 O ( N l o g N ) O(NlogN) O(NlogN),每次找当前最长串,然后再将当前贡献存进去,相当于区间查询,单点修改。而这次,每个01串都有很多小区间,其实就是把单点修改改成区间覆盖的线段树就可以了。看到1e9的数据范围,考虑离散化或动态开点。我们直接模拟LIS的过程,扫描每个串的小区间,找出当前长度值最大的那个值,并记录01串序号,将当前01串所有区间覆盖成当前最值,一直模拟就可以。

Code

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned int ul;
typedef pair<int, int> PII;
const ll inf = 1e18;
const int N = 6e5 + 10;
const int M = 1e6 + 10;
const ll mod = 1e9 + 7;
const double eps = 1e-8;

#define lowbit(i) (i & -i)
#define Debug(x) cout << (x) << endl
#define fi first
#define se second
#define mem memset
#define endl '\\n'

namespace StandardIO {
    template<typename T>
    inline void read(T &x) {
        x = 0; T f = 1;
        char c = getchar();
        for (; c < '0' || c > '9'; c = getchar()) if (c == '-') f = -1;
        for (; c >= '0' && c <= '9'; c = getchar()) x = x * 10 + c - '0';
        x *= f;
    }

    template<typename T>
    inline void write(T x) {
        if (x < 0) putchar('-'), x *= -1;
        if (x >= 10) write(x / 10);
        putchar(x % 10 + '0');
    }
}

namespace Seg {
#define ls (u<<1)
#define rs (u<<1|1)
#define mid ((l+r)>>1)
    PII ma[N<<2], tag[N<<2];
    void push_up(int u) {
        ma[u] = max(ma[u<<1], ma[u<<1|1]);
    }
    void push_down(int u) {
        if (tag[u].fi) {
            tag[u<<1] = max(tag[u<<1], tag[u]);
            tag[u<<1|1] = max(tag[u<<1|1], tag[u]);
            ma[u<<1] = max(ma[u<<1], tag[u]);
            ma[u<<1|1] = max(ma[u<<1|1], tag[u]);
            tag[u] = {0, 0};
        }
    }
    void modify(int u, int ql, int qr, int l, int r, PII val) {
        if (ql <= l && qr >= r) {
            ma[u] = max(ma[u], val);
            tag[u] = max(tag[u], val);
            return;
        }
        push_down(u);
        if (ql <= mid) modify(ls, ql, qr, l, mid, val);
        if (qr > mid) modify(rs, ql, qr, mid+1, r, val);
        push_up(u);
    }
    PII query(int u, int ql, int qr, int l, int r) {
        if (ql <= l && qr >= r) return ma[u];
        PII ans = {0, 0};
        push_down(u);
        if (ql <= mid) ans = max(ans, query(u<<1, ql, qr, l, mid));
        if (qr > mid) ans = max(ans, query(u<<1|1, ql, qr, mid+1, r));
        return ans;
    }
#undef mid
#undef ls
#undef rs
}
using namespace Seg;
int b[N], pre[N], vis[N];
vector<PII> ve[N];
inline void solve() {
    int n, m; cin >> n >> m;
    int tot = 0;
    for (int i = 1; i <= m; i++) {
        int id, l, r; cin >> id >> l >> r;
        ve[id].push_back({l, r});
        b[++tot] = l;
        b[++tot] = r;
    }
    sort(b+1, b+tot+1);
    tot = unique(b+1, b+tot+1) - b - 1;
    int pos = 0, ans = 0;
    for (int i = 1; i <= n; i++) {
        PII Max = {0, 0};
        for (auto &it : ve[i]) {
            it.fi = lower_bound(b+1, b+tot+1, it.fi) - b;
            it.se = lower_bound(b+1, b+tot+1, it.se) - b;
            PII tmp = query(1, it.fi, it.se, 1, tot);
            Max = max(Max, tmp);
        }
        pre[i] = Max.se;
        Max.se = i;
        Max.fi++;
        if (Max.fi > ans) {
            ans = Max.fi;
            pos = i;
        }
        for (auto &it : ve[i]) {
            modify(1, it.fi, it.se,1, tot, Max);
        }
    }

    cout << n - ans << endl;
    while (pos) {
        vis[pos] = 1;
        pos = pre[pos];
    }
    for (int i = 1; i <= n; i++) if (!vis[i]) cout << i << ' ';
    cout << endl;
}

signed main() {
    ios_base::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
#ifdef ACM_LOCAL
    freopen("input", "r", stdin);
    freopen("output", "w", stdout);
    signed test_index_for_debug = 1;
    char acm_local_for_debug = 0;
    do {
        if (acm_local_for_debug == '$') exit(0);
        if (test_index_for_debug > 20)
            throw runtime_error("Check the stdin!!!");
        auto start_clock_for_debug = clock();
        solve();
        auto end_clock_for_debug = clock();
        cout << "Test " << test_index_for_debug << " successful" << endl;
        cerr << "Test " << test_index_for_debug++ << " Run Time: "
             << double(end_clock_for_debug - start_clock_for_debug) / CLOCKS_PER_SEC << "s" << endl;
        cout << "--------------------------------------------------" << endl;
    } while (cin >> acm_local_for_debug && cin.putback(acm_local_for_debug));
#else
    solve();
#endif
    return 0;
}

以上是关于Codeforces Round #737 (Div. 2) D. Ezzat and Grid 线段树模拟最长上升子序列的主要内容,如果未能解决你的问题,请参考以下文章

Codeforces Round #737 (Div. 2) 题解

Codeforces Round #737 (Div. 2) 题解

Codeforces Round #737 (Div. 2) 题解

Codeforces Round #737 (Div. 2) Ezzat and Grid(线段树优化dp)

Codeforces Round #737 (Div. 2)(补题)

Codeforces Round #737 (Div. 2) C