CF1557 D. Ezzat and Grid(dp+线段树)

目录

Description

\(n\)\(01\) 串, 其中有 \(m\) 个区间 \([l,r]\) 内的字符为 \(1\)

如果两行之中有任意一个位置 \(x\), 都为 \(1\), 那么这两行相互连接,求删除尽可能少的行,使得每一行都相互连接

State

\(1<=n,m<=3*10^{5}\)

\(1<=l<=r<=10^9\)

Input

3 6
1 1 1
1 7 8
2 7 7
2 15 15
3 1 1
3 15 15

Output

0

Solution

题目就是一道简单 dp + 记录答案

\(dp[i]=max(dp[j]+1),j∈[1,i-1]\)

如果找到了第 \(j\) 行,使得 \(dp[i]\) 最大,我们需要知道的值有 \((dp[j],j)\) 两个;

那么该怎样找到这个 \(j\) 呢,如果第 \(i\) 行的任意一个区间与 \(j\) 上的区间重合就可以,而第 \(i\) 行上的区间更新上这个最大值就可以保证之后最大值的成立

\(hack:\) 线段树的大小为区间的端点数

Code

const int N = 3e5 + 5;

    ll n, m, _;
    int i, j, k;
    vector<pii> a[N];
    struct Node
    {
        int l, r;
        pii maxx, lazy;
        #define lson id << 1
        #define rson id << 1 | 1
        void update(pii x)
        {
            lazy = max(lazy, x);
            maxx = max(maxx, x);
        }
    }t[N << 3];

void push_up(int id)
{
    t[id].maxx = max(t[lson].maxx, t[rson].maxx);
}

void push_down(int id)
{
    pii &x = t[id].lazy;
    if(x.fi){
        t[lson].update(x);
        t[rson].update(x);
        x = {0, 0};
    }
}

void build(int l, int r, int id)
{
    t[id].l = l, t[id].r = r;
    t[id].maxx = t[id].lazy = {0, 0};
    if(l == r){
        return ;
    }
    else{
        int mid = l + r >> 1;
        build(l, mid, lson);
        build(mid + 1, r, rson);
        return ;
    }
}

void update(int l, int r,int id, pii x)
{
    int L = t[id].l, R = t[id].r;
    if(L >= l && r >= R){
        return t[id].update(x);
    }
    else{
        int mid = L + R >> 1;
        push_down(id);
        if(mid >= l) update(l, r, lson, x);
        if(r >= mid + 1) update(l, r, rson, x);
        push_up(id);
    }
}

pii query(int l, int r, int id)
{
    int L = t[id].l, R = t[id].r;
    if(L >= l && r >= R){
        return t[id].maxx;
    }
    else{
        pii ans(0, 0);
        int mid = L + R >> 1;
        push_down(id);
        if(mid >= l) ans = max(ans, query(l, r, lson));
        if(r >= mid + 1) ans = max(ans, query(l, r, rson));
        push_up(id);
        return ans;
    }
}

vector<int> v;
int getid(int x)
{
    return lower_bound(v.begin(), v.end(), x) - v.begin() + 1;
}

int recreat()
{
    sort(v.begin(), v.end());
    v.erase(unique(v.begin(), v.end()), v.end());
    for(int i = 1; i <= n; i ++){
        for(auto &it : a[i]){
            it.fi = getid(it.fi);
            it.se = getid(it.se);
        }
    }
    return v.size();
}

int pre[N], dp[N], vis[N];
void print()
{
    pii maxx(0, 0);
    for(int i = 1; i <= n; i ++){
        maxx = max(maxx, {dp[i], i});
    }
    int id = maxx.se;
    while(id != -1){
        vis[id] = 1;
        id = pre[id];
    }
    vector<int> ans;
    rep(i, 1, n){
        if(! vis[i]) ans.pb(i);
    }
    int sz = ans.size();
    pd(sz);
    rep(i, 0, sz - 1){
        printf("%d ", ans[i]);
    }
}

signed main()
{
    //IOS;
    while(~ sdd(n, m)){
        int id, l, r;
        rep(i, 1, m){
            sddd(id, l, r);
            a[id].pb(pii(l, r));
            v.pb(l), v.pb(r);
        }
        int sz = recreat();
        build(1, sz, 1);
        fill_n(pre, N, -1);
        rep(i, 1, n){
            pii ans(0, 0);
            for(auto it : a[i]){
                int l = it.fi, r = it.se;
                ans = max(ans, query(l, r, 1));
            }
            dp[i] = dp[ans.se] + 1;
            pre[i] = ans.se;
            ans = {dp[i], i};
            for(auto it : a[i]){
                int l = it.fi, r = it.se;
                update(l, r, 1, ans);
            }
        }
        print();
    }
    //PAUSE;
    return 0;
}
posted @ 2021-09-03 19:45  Bcoi  阅读(54)  评论(0)    收藏  举报