Codeforces

题意:

  给出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);
        }
    }
}
C++
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)
        }
    }
}
Go
原文地址:https://www.cnblogs.com/Pneuis/p/15164226.html