原题链接: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;
}