題目
給你一個高N(≤3⋅105)長109的 01 矩陣。01矩陣會由m(≤3⋅105)個區間(hi,li,ri)來表示1的位置。例如 n=3,=6時,且區間為(1,1,1),(1,7,8),(2,7,7),(2,15,15),(3,1,1),(3,15,15)這樣的話該矩陣就會長的像下面這樣:
題解
有經驗的話就可以很輕鬆地看出套個線段樹優化就結束了~
但是!因為我壓根就忘記了線段樹優化要怎麼用,所以我根本沒發現他可以套線段樹優化(x。
因為沒有發現他是線段樹優化,所以我就想出了另外一個有點神奇的作法:掃描線+建圖
#include "bits/stdc++.h"
#define f first
#define s second
#define endl '\n'
#define pb push_back
#define pii pair<int, int>
#define all(x) x.begin(), x.end()
#define FFOR(i, a, b) for(int i = a; i <= b; i ++)
#define FOR(i, n) FFOR(i, 1, n)
#define loli ios_base::sync_with_stdio(false), cin.tie(0);
using namespace std;
const int maxn = 3e5 + 50;
int n, m, q;
int dep[maxn], ans, pre[maxn], cnt[maxn];
vector<int> vc[maxn], vans;
bitset<maxn> vis;
map<int, vector<int>> mp;
set<int> st;
void dfs(int x) {
for(int i : vc[x]) {
if(!dep[i] and i != x) dfs(i);
if(dep[i] + 1 > dep[x]) {
pre[x] = i;
dep[x] = dep[i] + 1;
}
ans = max(ans, dep[x]);
}
}
void solve() {
st.insert(0), st.insert(n + 1);
for(auto tmp : mp) {
int x = tmp.f;
vector<int> v = tmp.s;
sort(all(v)); // 先移除掉失效區間再加入區間
for(int i : v) {
if(i < 0) {
cnt[-i] --;
if(cnt[-i] == 0) st.erase(-i);
auto it = st.lower_bound(-i);
vc[*it].pb(*prev(it));
}
else {
if(!cnt[i]) st.insert(i);
cnt[i] ++;
auto it = st.lower_bound(i);
vc[i].pb(*prev(it));
vc[*next(it)].pb(i);
}
}
}
FOR(i, n + 1) {
if(!dep[i]) dfs(i);
}
cout << n - ans + 1 << endl;
int x = n + 1;
while(x != 0) {
vans.pb(x);
x = pre[x];
}
sort(all(vans));
for(int i : vans) vis[i] = 1;
FOR(i, n) if(!vis[i]) cout << i << ' '; cout << endl;
}
void input() {
cin >> n >> m;
FOR(i, m) {
int a, b, c;
cin >> a >> b >> c;
mp[b].pb(a);
mp[c + 1].pb(-a);
}
}
signed main(){
loli;
input();
solve();
}