题意:
给出n行,109列的01矩阵,矩阵中的1是由m段连续的横向区间构成。问至少删除多少行,使得剩下的任意两行之间至少有同一列都为1;并输出删除方案。
题解:
假定某两行有同一列是1,那么称这两行相连。
即使有109列,但是成段的1也只有m段而已。
总体是dp的思想:从上往下扫每一行,当前行的答案是它上面和它相连的行的答案的最大值+1。
用线段树优化dp,维护每个区间的答案最大值以及最大值时的行号。
#include <bits/stdc++.h> using namespace std; const int N = 3e5+10; typedef pair<int, int> P; int n, m, tot; int p, l, r; int last[N]; int visit[N]; vector<int> v; vector<P> g[N]; P lzy[N<<4], tree[N<<4]; int get_pos(int x) { return lower_bound(v.begin(), v.end(), x) - v.begin() + 1; } void push_up(int id) { P val = max(tree[id<<1], tree[id<<1|1]); tree[id] = max(tree[id], val); } void push_down(int id) { if(lzy[id].first == 0) return; lzy[id<<1] = max(lzy[id<<1], lzy[id]); lzy[id<<1|1] = max(lzy[id<<1|1], lzy[id]); tree[id<<1] = max(tree[id<<1], lzy[id]); tree[id<<1|1] = max(tree[id<<1|1], lzy[id]); lzy[id] = make_pair(0, 0); } void insert(int id, int l, int r, int ql, int qr, P val) { if(ql <= l && r <= qr) { tree[id] = max(tree[id], val); lzy[id] = max(lzy[id], val); return; } push_down(id); int mid = (l + r) >> 1; if(ql <= mid) insert(id<<1, l, mid, ql, qr, val); if(qr > mid) insert(id<<1|1, mid+1, r, ql, qr, val); push_up(id); } P query(int id, int l, int r, int ql, int qr) { if(ql <= l && r <= qr) { return tree[id]; } push_down(id); int mid = (l + r) >> 1; P now = make_pair(0, 0); if(ql <= mid) now = query(id<<1, l, mid, ql, qr); if(qr > mid) now = max(now, query(id<<1|1, mid+1, r, ql, qr)); push_up(id); return now; } int main() { scanf("%d%d", &n, &m); while(m--) { scanf("%d%d%d", &p, &l, &r); g[p].push_back(make_pair(l, r)); v.push_back(l); v.push_back(r); } sort(v.begin(), v.end()); v.erase(unique(v.begin(), v.end()), v.end()); tot = v.size(); P ans = make_pair(0, 0); for(int i = 1; i <= n; i++) { P res = make_pair(0, 0); for(int j = 0; j < g[i].size(); j++) { l = get_pos(g[i][j].first); r = get_pos(g[i][j].second); res = max(res, query(1, 1, tot, l, r)); } last[i] = res.second; res.first++; res.second = i; ans = max(ans, res); for(int j = 0; j < g[i].size(); j++) { l = get_pos(g[i][j].first); r = get_pos(g[i][j].second); insert(1, 1, tot, l, r, res); } } int pos = ans.second; while(pos) { visit[pos] = 1; pos = last[pos]; } printf("%d ", n - ans.first); bool flag = false; for(int i = 1; i <= n; i++) { if(!visit[i]) { if(flag) printf(" "); flag = true; printf("%d", i); } } }
package main import ( "io" "os" "fmt" "sort" "bufio" ) const N int = 3e5+10 var n, m, tot int var p, l, r int var last, visit [N]int var v sort.IntSlice var g [][]pair var lzy, tree [N<<4]pair type pair struct { first, second int } func max(x, y pair) pair { if x.first > y.first { return x } if x.first == y.first { if x.second > y.second { return x } } return y } func get_pos(x int) int { l := 0 r := tot - 1 for l <= r { mid := (l + r) >> 1 if v[mid] < x { l = mid + 1 } else { r = mid - 1 } } return l + 1 } func push_up(id int) { val := max(tree[id<<1], tree[id<<1|1]) tree[id] = max(tree[id], val) } func push_down(id int) { if lzy[id].first == 0 { return } lzy[id<<1] = max(lzy[id<<1], lzy[id]) lzy[id<<1|1] = max(lzy[id<<1|1], lzy[id]) tree[id<<1] = max(tree[id<<1], lzy[id]) tree[id<<1|1] = max(tree[id<<1|1], lzy[id]) lzy[id] = pair{0, 0} } func insert(id, l, r, ql, qr int, val pair) { if ql <= l && r <= qr { tree[id] = max(tree[id], val) lzy[id] = max(lzy[id], val) return } push_down(id) mid := (l + r) >> 1 if ql <= mid { insert(id<<1, l, mid, ql, qr, val) } if qr > mid { insert(id<<1|1, mid+1, r, ql, qr, val) } push_up(id) } func query(id, l, r, ql, qr int) pair { if ql <= l && r <= qr { return tree[id] } push_down(id) mid := (l + r) >> 1 now := pair{0, 0} if ql <= mid { now = query(id<<1, l, mid, ql, qr) } if qr > mid { now = max(now, query(id<<1|1, mid+1, r, ql, qr)) } push_up(id) return now } func main() { var input io.Reader = bufio.NewReader(os.Stdin) fmt.Fscan(input, &n) for i := 1; i <= n + 1; i++ { tmp := []pair{} g = append(g, tmp) } for fmt.Fscan(input, &m); m > 0; m-- { fmt.Fscan(input, &p) fmt.Fscan(input, &l) fmt.Fscan(input, &r) g[p] = append(g[p], pair{l, r}) v = append(v, l, r) } sort.Ints(v) l = 0 for i, _ := range v { if i == 0 || v[i] != v[i-1] { v[l] = v[i] l++ } } v = v[0:l] tot = len(v) ans := pair{0, 0} for i := 1; i <= n; i++ { res := pair{0, 0} for _, val := range g[i] { l = get_pos(val.first) r = get_pos(val.second) res = max(res, query(1, 1, tot, l, r)) } last[i] = res.second res.first++ res.second = i ans = max(ans, res) for _, val := range g[i] { l = get_pos(val.first) r = get_pos(val.second) insert(1, 1, tot, l, r, res) } } pos := ans.second for pos > 0 { visit[pos] = 1 pos = last[pos] } fmt.Println(n - ans.first) flag := false for i := 1; i <= n; i++ { if visit[i] == 0 { if flag { fmt.Print(" ") } flag = true fmt.Print(i) } } }