题意:
有n个区域,k种颜色,每个区域任选一种颜色,问最多共有多长的区域能被k种颜色覆盖,并输出一种方案
思路:
贪心的考虑,我们要让尽量多的重叠区间个数>=k的区间有k种颜色。想法很容易想到,主要去考虑如何算答案和方案。
- 将2*n个点排序,位置相同时右端点排在左端点之前。 将未使用过的颜色放在队列中 如果当前队列为空,那么说明该点到上一个点之间被覆盖过k次
- 如果当前点是左端点
- 如果还有颜色没有分配,那么给这个区间分配颜色;
- 如果没有颜色了,就将这个区间放到栈里待定(注意这里是不能随便给这个区间分配颜色的,他有可能影响后面的区间)。
- 如果当前点是右端点
- 如果这个区间分配过颜色,那么将这颜色收回
- 如果没有分配过颜色,那么说明这区间没有贡献,随便给他分配一个颜色即可
- 如果当前还有颜色没有分配,且存在待定的区间,那么给这些待定的区间分配颜色(这里注意待定的区间可能也被分配过颜色,如果被分配过了,跳过)
代码
#include<bits/stdc++.h>
#define INF 0x3f3f3f3f
#define lowbit(x) x&(-x)
#define pb push_back
using namespace std;
typedef long long ll;
typedef pair<int,int>P;
typedef unsigned long long ull;
struct Node
{
int x,f,id;
bool operator <(Node a)
{
if(a.x==x)return f<a.f;
return x<a.x;
}
}node[400010];
int ans[200010];
int main(){
int t;scanf("%d",&t);
while(t--)
{
int n,k;scanf("%d%d",&n,&k);
int tot=0,res=0;
for(int i=1;i<=n;i++)
{
int l,r;scanf("%d%d",&l,&r);
node[++tot]={l,1,i};
node[++tot]={r,-1,i};
ans[i]=0;
}
queue<int>q;
for(int i=1;i<=k;i++)q.push(i);
stack<int>sk;
sort(node+1,node+1+tot);
for(int i=1;i<=tot;i++)
{
if(q.empty())res+=node[i].x-node[i-1].x;
if(node[i].f==1)
{
if(q.empty())sk.push(node[i].id);
else
{
ans[node[i].id]=q.front();q.pop();
}
}
else
{
if(ans[node[i].id])q.push(ans[node[i].id]);
else ans[node[i].id]=1;
}
while(!q.empty()&&!sk.empty())
{
int p=sk.top();sk.pop();
if(ans[p])continue;
ans[p]=q.front();q.pop();
}
}
printf("%d\n",res);
int flag=0;
for(int i=1;i<=n;i++)
{
if(flag)printf(" ");
printf("%d",ans[i]);
flag=1;
}
printf("\n");
}
return 0;
}