2018 Xuzhou H - Rikka with A Long Colour Palette

4 篇文章 0 订阅

 贪心策略:

维护一个当前未出现的颜色的集合

再维护一个目前所有颜色最晚出现位置的集合

对颜色区间的左右边界进行离散化,再从左向右遍历。对于一个起点,若未出现的颜色的集合非空,则填上这个集合中任意一个颜色。(任意性的证明可以这样:对于一个最优的方案,我们任意交换两个颜色的所有染色区间,所得到的方案仍是最优的,那么这个任意性的正确性便可通过交换这两个颜色证明 )。若未出现的颜色的集合为空,则染色为结束位置最早的颜色(证明如下:若染成其他颜色,得到一个最终方案,我们可以将这两个颜色交换。得到的长度一定 >= 原方案  )。贪心正确性得证。

具体的实现细节:

出现的颜色最晚位置用 优先队列来维护。那么存在一个遇到右端点删除颜色的时候无法进行实时删除的问题,我们的解决方案就是         while( que.top().first <= ve[i] ) que.pop(); // 若 结束位置小于等于当前位置,说明这个点已经被删除。

坑点:行末不可以输出空格,我再也不侥幸了,CF都可能因为这个判错,怎能指望现场赛呢?

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef int lint;
typedef pair<lint,lint> pii;
const lint maxn = 400005;
vector<lint> ve;
vector<pii> seg;
void discrete(){
    sort( ve.begin(),ve.end() );
    ve.erase( unique(ve.begin(),ve.end()),ve.end() );
}
lint H( lint x ){
    return lower_bound( ve.begin(),ve.end(),x ) - ve.begin();
}
vector<lint> ves[2*maxn];
vector<lint> vet[2*maxn];
stack<lint> st;
priority_queue<pii,vector<pii>,greater<pii>> que;
lint color[maxn],vis[maxn];
int main(){
    lint T,n,k,l,r,ans;
    scanf("%d",&T);
    while( T-- ){
        scanf("%d%d",&n,&k);
        ve.clear();seg.clear();
        for( lint i= 1;i <= k;i++ ) vis[i] = 0;
        for( lint i = 0;i < 2*n;i++ ){
            ves[i].clear();
            vet[i].clear();
        }
        while( que.size() ) que.pop();
        while( st.size() ) st.pop();
        for( lint i = 1;i <= k;i++ ) st.push(i);
        ans  = 0;
        for( lint i = 1;i <= n;i++ ){
            scanf("%d%d",&l,&r);
            seg.push_back( pii( l,r ) );
            ve.push_back( l );
            ve.push_back( r );
        }
        discrete();
        for( lint i = 0;i < seg.size();i++ ){
            lint x = seg[i].first;
            lint y = seg[i].second;
            ves[ H(x) ].push_back( i+1 );
            vet[ H(y) ].push_back( i+1 );
        }
        lint cnt = 0;
        for( lint i = 0;i < ve.size();i++ ){
            lint x = ve[i];
            if( i > 0 && cnt == k ){
                ans += ve[i] - ve[i-1];
            }
            for( lint j = 0;j < vet[i].size();j++ ){
                vis[ color[vet[i][j] ] ]--;
                if( !vis[ color[ vet[i][j] ] ] ) {
                    st.push(color[vet[i][j]]);
                    cnt--;
                }
            }
            for( lint j = 0;j < ves[i].size();j++ ){
                lint id = ves[i][j];
                if( st.size() ){
                    color[id] = st.top();
                    st.pop();cnt++;
                    que.push( pii( seg[id-1].second,color[id] ) );
                    vis[ color[id] ]++;
                }else{
                    while( que.top().first <= ve[i] ) que.pop();
                    pii cur = que.top();
                    que.pop();
                    color[id] = cur.second;
                    vis[ cur.second ]++;
                    cur.first = max( cur.first,seg[id-1].second );
                    que.push( cur );
                }
            }
        }
        printf("%d\n",ans);
        printf("%d",color[1]);
        for( lint i = 2;i <= n;i++ ){
            printf(" %d",color[i]);
        }
        printf("\n");
    }
    return 0;
}

[close]

 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值