贪心策略:
维护一个当前未出现的颜色的集合
再维护一个目前所有颜色最晚出现位置的集合
对颜色区间的左右边界进行离散化,再从左向右遍历。对于一个起点,若未出现的颜色的集合非空,则填上这个集合中任意一个颜色。(任意性的证明可以这样:对于一个最优的方案,我们任意交换两个颜色的所有染色区间,所得到的方案仍是最优的,那么这个任意性的正确性便可通过交换这两个颜色证明 )。若未出现的颜色的集合为空,则染色为结束位置最早的颜色(证明如下:若染成其他颜色,得到一个最终方案,我们可以将这两个颜色交换。得到的长度一定 >= 原方案 )。贪心正确性得证。
具体的实现细节:
出现的颜色最晚位置用 优先队列来维护。那么存在一个遇到右端点删除颜色的时候无法进行实时删除的问题,我们的解决方案就是 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]