CF1557D Ezzat and Grid 题解

发布于 2021-08-10  97 次阅读


题意

题目链接

给定 $n$ 行 01 串,其中有 $m$ 个区间为 $1$​。删除若干 01 串使剩余串美丽,若干条 01 串美丽当且仅当任意相邻两个 01 串至少有相同的一位均为 $1$。

$n,m\le 3\times10^5$。

解析

考虑记 $f_i$ 为以第 $i$ 串结尾的最长美丽串的长度。发现 $f_i=f_j+1,j\in[1,i)$ 当且仅当第 $i$ 串和 $j$ 串有相同位的 $1$​,发现离散化后串一共就只有 $6\times10^5$ 位,我们考虑将贡献打在 01 串的具体位上。

记 $f_{i,j}$ 为当前遍历到第 $i$ 个串,其中最后一个串的第 $j$ 位上为 $1$ 的最大贡献,容易发现 $i$ 实际没什么用。那么我们考虑对于 $j$ 建一棵线段树,遍历到第 $i$ 个串时,我们在线段树上查询第 $i$ 个串所有 $1$ 位置的答案并取最大值再加一作为以当前串结尾的答案,再用这个答案去更新该串的所有 $1$ 位置即可。

由于要输出方案,线段树改成 pair,分别存答案和产生这个答案的串即可。

代码

#include<bits/stdc++.h>
#define pi pair<int,int>
#define fi first
#define se second
#define mk make_pair
#define ls x<<1
#define rs x<<1|1
using namespace std;
const int N=3e5+5;
pi tr[N<<3],tag[N<<3];
int n,m,pre[N],b[N<<1],cnt,mx;
int ans,ansp;
vector<pi> vec[N];
inline pi Max(pi x,pi y){
    if(x.fi>y.fi) return x;
    return y;
}
inline void pushdown(int x){
    if(!tag[x].fi) return;
    tr[ls]=tag[x],tr[rs]=tag[x];
    tag[ls]=tag[x],tag[rs]=tag[x];
    tag[x]=mk(0,0);
}
inline void pushup(int x){
    tr[x]=Max(tr[ls],tr[rs]);
}
inline pi query(int x,int l,int r,int L,int R){
    if(l>=L&&r<=R) return tr[x];
    int mid=(l+r)>>1;
    pushdown(x);
    if(L<=mid&&R>mid) return Max(query(ls,l,mid,L,R),query(rs,mid+1,r,L,R));
    if(L<=mid) return query(ls,l,mid,L,R);
    return query(rs,mid+1,r,L,R);
}
inline void modify(int x,int l,int r,int L,int R,pi k){
    if(l>=L&&r<=R){tr[x]=k;tag[x]=k;return;}
    int mid=(l+r)>>1;
    pushdown(x);
    if(L<=mid) modify(ls,l,mid,L,R,k);
    if(R>mid) modify(rs,mid+1,r,L,R,k);
    pushup(x);
}
bool vis[N];
int main(){
    scanf("%d%d",&n,&m);
    for(int i=1,x,l,r;i<=m;i++){
        scanf("%d%d%d",&x,&l,&r);
        vec[x].push_back(mk(l,r));
        b[++cnt]=l;b[++cnt]=r;
    }
    sort(b+1,b+1+cnt);
    cnt=unique(b+1,b+1+cnt)-b-1;
    for(int i=1;i<=n;i++){
        for(auto &x:vec[i]){
            x.fi=lower_bound(b+1,b+1+cnt,x.fi)-b;
            x.se=lower_bound(b+1,b+1+cnt,x.se)-b;
        }
    }//离散化
    for(int i=1;i<=n;i++){
        mx=-1;
        for(auto x:vec[i]){//求当前串的答案
            pi t=query(1,1,cnt,x.fi,x.se);
            if(t.fi>mx){mx=t.fi;pre[i]=t.se;}
        }
        if(mx+1>ans){//更新全局答案
            ans=mx+1;
            ansp=i;
        }
        for(auto x:vec[i]){//更新对应位置的答案
            pi t=mk(mx+1,i);
            modify(1,1,cnt,x.fi,x.se,t);
        }
    }
    printf("%d\n",n-ans);
    for(int i=ansp;i;i=pre[i]) vis[i]=1;
    for(int i=1;i<=n;i++){
        if(!vis[i]) printf("%d ",i);
    }
    return 0;
}

掉大分,哈哈。


月流华 岁遗沙 万古吴钩出玉匣