题目链接:https://codeforces.com/contest/1557/problem/D
分析
设
d
p
[
i
]
dp[i]
dp[i]表示从
1
1
1到
i
i
i行最多连几行(取第
i
i
i行),
p
r
e
[
i
]
pre[i]
pre[i]表示取了
i
i
i并且前面是最优取法情况下的前一行。于是我们得到了
p
r
e
[
i
]
pre[i]
pre[i]数组即可得到答案。
可以用线段树来维护,每个区间有一个
{
v
a
l
u
e
,
l
a
s
t
}
\{value, last\}
{value,last},表示到该区间的最大取的行数,以及取到这个区间的最新的行号。
那么对于每一行我们找到最大的
v
a
l
u
e
value
value值,这一行的
p
r
e
[
i
]
pre[i]
pre[i]值就是这个这个最大值的
l
a
s
t
last
last值。
由于数据范围较大,建树前需要先离散化,每个点初始值可以为
{
0
,
−
1
}
\{0, -1\}
{0,−1}。
代码
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
#define fi first
#define se second
#define pb push_back
#define MP make_pair
const int N = 3e5 + 10;
const int M = 2e5 + 10;
const ll mod = 1e9 + 7;
int n,m;
int pre[N],vis[N];
vector<pii> g[N];
int tot[N<<1],cnt;
pii t[N<<3],lazy[N<<3];
void push_up(int rt)
{
t[rt] = max(t[rt << 1], t[rt << 1 | 1]);
return ;
}
void push_down(int rt)
{
if(lazy[rt] == MP(0, -1)) return ;
t[rt << 1] = max(t[rt << 1], lazy[rt]);
t[rt << 1 | 1] = max(t[rt << 1 | 1], lazy[rt]);
lazy[rt << 1] = max(lazy[rt << 1], lazy[rt]);
lazy[rt << 1 | 1] = max(lazy[rt << 1 | 1], lazy[rt]);
lazy[rt] = MP(0, -1);
return ;
}
void build(int rt, int l, int r)
{
if(l == r)
{
t[rt] = lazy[rt] = MP(0, -1);
return ;
}
t[rt] = lazy[rt] = MP(0, -1);
int mid = (l + r) >> 1;
build(rt << 1, l, mid);
build(rt << 1 | 1, mid + 1, r);
return ;
}
pii query(int rt, int l, int r, int ql, int qr)
{
if(l >= ql && r <= qr)
{
return t[rt];
}
push_down(rt);
pii res = MP(0, -1);
int mid = (l + r) >> 1;
if(ql <= mid) res = max(res, query(rt << 1, l, mid, ql, qr));
if(qr > mid) res = max(res, query(rt << 1 | 1, mid + 1, r, ql, qr));
return res;
}
void update(int rt, int l, int r, int ql, int qr, pii x)
{
if(l >= ql && r <= qr)
{
t[rt] = max(t[rt], x);
lazy[rt] = max(lazy[rt], x);
return ;
}
push_down(rt);
int mid = (l + r) >> 1;
if(ql <= mid) update(rt << 1, l, mid, ql, qr, x);
if(qr > mid) update(rt << 1 | 1, mid + 1, r, ql, qr, x);
push_up(rt);
return ;
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++)
{
int x,l,r;
scanf("%d%d%d",&x,&l,&r);
tot[++cnt] = l;
tot[++cnt] = r;
g[x].pb(MP(l, r));
}
sort(tot + 1, tot + 1 + cnt);//开始离散化
cnt = unique(tot + 1, tot + 1 + cnt) - tot - 1;
for(int i=1;i<=n;i++)
for(int j=0;j<g[i].size();j++)
{
g[i][j].fi = lower_bound(tot + 1, tot + 1 + cnt, g[i][j].fi) - tot;
g[i][j].se = lower_bound(tot + 1, tot + 1 + cnt, g[i][j].se) - tot;
}
build(1, 1, cnt);
int maxn = 0, maxi;
for(int i=1;i<=n;i++)
{
pii tmp = MP(0, -1);
for(int j=0;j<g[i].size();j++)
tmp = max(tmp, query(1, 1, cnt, g[i][j].fi, g[i][j].se));
pre[i] = tmp.se;
for(int j=0;j<g[i].size();j++)
update(1, 1, cnt, g[i][j].fi, g[i][j].se, MP(tmp.fi + 1, i));
if(tmp.fi + 1 > maxn) maxn = tmp.fi + 1, maxi = i;
}
for(int i=maxi;i>0;i=pre[i]) vis[i] = 1;
printf("%d\n",n - maxn);
for(int i=1;i<=n;i++) if(vis[i] == 0) printf("%d ",i);
return 0;
}