思路
线段树优化
表示线段能组成漂亮序列最多的行数。那么每次转移的时候,区间上查找与线段对应位有的所有线段,选取最大的一个线段,那么。
考虑用线段树去优化,区间上找最大的,然后得到,接着用覆盖线段的区间。因为这个只和上一个状态有关,所以可以直接覆盖。
code:
#include<bits/stdc++.h> using namespace std; typedef long long ll; const int maxn=3e5+7; pair<int,int>t[maxn<<3],ac; bool re[maxn<<3]; #define lson l,mid,rt<<1 #define rson mid+1,r,rt<<1|1 inline void pushup(int rt) { if(re[rt]) { t[rt<<1]=t[rt<<1|1]=t[rt]; re[rt<<1]=re[rt<<1|1]=1; re[rt]=0; } } inline void update(int l,int r,int rt,int x,int y) { if(x<=l&&r<=y) { t[rt]=ac; re[rt]=1; return; } pushup(rt); int mid=(l+r)/2; if(x<=mid) update(lson,x,y); if(y>mid) update(rson,x,y); t[rt]=max(t[rt<<1],t[rt<<1|1]); } inline pair<int,int>query(int l,int r,int rt,int x,int y) { if(x<=l&&r<=y) return t[rt]; pushup(rt); int mid=(l+r)/2; if(y<=mid) return query(lson,x,y); else if(x>mid) return query(rson,x,y); else return max(query(lson,x,y),query(rson,x,y)); } vector<pair<int,int> >g[maxn]; int b[maxn<<1],tot,last[maxn]; bool vis[maxn]; int main() { cin.sync_with_stdio(false), cin.tie(nullptr),cout.tie(nullptr); int n,m; cin>>n>>m; for(int i=1,row,x,y;i<=m;++i) { cin>>row>>x>>y; g[row].emplace_back(x,y); b[++tot]=x; b[++tot]=y; } sort(b+1,b+1+tot); int r=unique(b+1,b+1+tot)-b; for(int i=1;i<=n;++i) for(auto &j:g[i]) { j.first=lower_bound(b+1,b+r,j.first)-b; j.second=lower_bound(b+1,b+r,j.second)-b; } for(int i=1;i<=n;++i) { pair<int,int>_max={0,-1}; for(auto &j:g[i]) _max=max(_max,query(1,r,1,j.first,j.second)); last[i]=_max.second,_max.second=i,++_max.first; ac=_max; for(auto &j:g[i]) update(1,r,1,j.first,j.second); } for(int i=t[1].second;i;i=last[i]) vis[i]=1; cout<<n-t[1].first<<'\n'; for(int i=1;i<=n;++i) if(!vis[i]) cout<<i<<' '; return 0; }