cf1557-D. Ezzat and Grid(离散化&线段树&pair复杂度&很多数据结构的基本操作)

总结收获

  1. 最重要的是知道怎么解决的,代码实在现在写不出来,可以先借鉴一下大佬的hhh。

题目

传送门

  1. 题意:n*1e9的01阵,m条线段(i,l,r)表示第i行[l,r]都为1,线段可能重复。一个漂亮矩阵定义为任意连续两行都至少有一列在这两行中都为1,求最少删去多少行,能使剩下的矩阵为漂亮矩阵。
    在这里插入图片描述
  2. 题解:不难想到,遍历每一行,每一行的上面一行应该是行数最多的漂亮矩阵的最后一行,然后线段树维护即可(具体的看代码)
    2.1 离散化:用unique而不用map
    2.2 pair<int,int>:能用就用,不用自己搞个结构体(大佬都在用pair),另外{x,y}似乎可以等价于make_pair(x,y)
    2.3 for(auto &i:g[x]):然后才可以修改值,否则知识取数操作。
    2.4 emplace_back算是puah_back的优化。
  3. 代码
//看懂之后仿一遍
#include <bits/stdc++.h>
#define pii pair<int, int>
// #define mp(x, y) make_pair(x, y)
#define dbg(x) cout << #x << "===" << x << endl
using namespace std;
const int N = 6e5 + 5;
int n, m, p, l, r;
int f[N], vis[N];
vector<pii> v[N];
vector<int> x;
pii mx[N << 2], tag[N << 2];
void pushdown(int p) {
    // if (!tag[p].first) return;
    mx[p << 1] = max(mx[p << 1], tag[p]);
    mx[p << 1 | 1] = max(mx[p << 1 | 1], tag[p]);
    tag[p << 1] = max(tag[p << 1], tag[p]);
    tag[p << 1 | 1] = max(tag[p << 1 | 1], tag[p]);
    tag[p] = {0, 0};
    // tag[p] = mp(0, 0);
}
void update(int p, int l, int r, int x, int y, pii k) {
    if (x <= l && r <= y) {
        mx[p] = max(mx[p], k), tag[p] = max(tag[p], k);
        return;
    }
    pushdown(p);
    int mid = (l + r) >> 1;
    if (mid >= x) update(p << 1, l, mid, x, y, k);
    if (mid < y) update(p << 1 | 1, mid + 1, r, x, y, k);
    mx[p] = max(mx[p << 1], mx[p << 1 | 1]);
}
pii query(int p, int l, int r, int x, int y) {
    if (x <= l && r <= y) return mx[p];
    pushdown(p);
    pii res = {0, 0};
    // pii res = mp(0, 0);
    int mid = (l + r) >> 1;
    if (mid >= x) res = max(res, query(p << 1, l, mid, x, y));
    if (mid < y) res = max(res, query(p << 1 | 1, mid + 1, r, x, y));
    return res;
}
int get(int &t) {
    return t = lower_bound(x.begin(), x.end(), t) - x.begin() + 1;
}
void solve() {
    cin >> n >> m;
    int i, j;
    for (i = 1; i <= m; i++) {
        cin >> p >> l >> r;
        v[p].push_back({l, r});
        // v[p].emplace_back(mp(l, r));
        x.emplace_back(l), x.emplace_back(r);
    }
    sort(x.begin(), x.end());
    //去重,同时更新x的大小(应该是只取前面的那么多数)
    x.resize(unique(x.begin(), x.end()) - x.begin());
    int k = x.size() - 1;
    pii ans = {0, 0};
    // pii ans = mp(0, 0);
    int L, R;
    for (i = 1; i <= n; i++) {
        pii y = {0, 0};
        // pii y = mp(0, 0);
        //&:可更改
        // dbg(i);
        for (auto &j : v[i]) {
            L = get(j.first), R = get(j.second);
            // cout << L << ' ' << R << endl;
            y = max(y, query(1, 1, k + 2, L, R));
        }
        // cout << y.first << " " << y.second << endl;
        y.first++;
        f[i] = y.second;
        y.second = i;
        ans = max(ans, y);
        for (auto j : v[i]) {
            L = j.first, R = j.second;
            // cout << L << " " << R << endl;
            update(1, 1, k + 2, L, R, y);
        }
    }
    cout << n - ans.first << "\n";
    for (i = ans.second; i; i = f[i]) vis[i] = 1;
    for (i = 1; i <= n; i++)
        if (!vis[i]) cout << i << " ";
}
signed main() {
    int T = 1;
    // cin >> T;
    while (T--) {
        solve();
    }
    return 0;
}
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值