题意:
给出n个数轴上的线段,进行每个线段染一种颜色,求混合有k种颜色的距离的和。
题解:
如果某一段被k条及以上线段覆盖,那么这一段一定是满足条件的,问题是如何求解方案数。
确定一条线段染什么颜色一定是根据左右端点判断得到的,所以我们只关心端点。
将左端点记为1,右端点记为-1,排序,相同的位置,右端点更靠前。
用一个队列保存没有染色的点,一开始所有颜色都在队列。
从小到大枚举位置
如果是左端点,并且队列不为空,我们就将这个线段染成队首的颜色
如果是右端点,如果这条线段染过色,就将该颜色放入队尾,进行回收
但是有几个细节要考虑
左端点时,如果所有颜色都染了,该染什么颜色?随便染吗?不是的,因为可能后面可能会用到,解决方法是将其将放入队列(栈)中,留着以后再用
什么时候用?
假如说处理完这个位置后,发现覆盖的颜色不够k种,这时我们就看之前存下来的线段,如果还没有被染色,就取出来染色。
这样就能利用起来所有的线段了
代码:
#include<bits/stdc++.h>
#define N 200010
#define INF 0x3f3f3f3f
#define eps 1e-10
#define pi 3.141592653589793
#define P 998244353
#define LL long long
#define pb push_back
#define cl clear
#define si size
#define lb lower_bound
#define ub upper_bound
#define mem(x) memset(x,0,sizeof x)
#define sc(x) scanf("%d",&x)
#define scc(x,y) scanf("%d%d",&x,&y)
#define sccc(x,y,z) scanf("%d%d%d",&x,&y,&z)
using namespace std;
struct dd
{
int x,y,id;
bool operator < (const dd d)const
{
return x==d.x?y<d.y:x<d.x;
}
}a[N<<1];
int col[N];
int main()
{
int T;
sc(T);
while(T--)
{
int n,m;
scc(n,m); int cn=0; mem(col);
for (int i=1;i<=n;i++)
{
int x,y;
scc(x,y);
a[++cn]=dd{x,1,i};
a[++cn]=dd{y,-1,i};
}
sort(a+1,a+cn+1);
queue<int> q; stack<int> st;
for (int i=1;i<=m;i++) q.push(i);
int t=0,k=1,prek=0,pret=0,ans=0;
while(k<=cn)
{
int p=k;
while(a[p].x==a[k].x)
{
if (a[p].y==-1)
{
int r=a[p].id;
if (col[r]!=0)
{
t--;
q.push(col[r]);
}else col[r]=1;
}
if (a[p].y==1)
{
int r=a[p].id;
if (t>=m) {st.push(r);} else
{
t++;
col[r]=q.front();
q.pop();
}
}
p++;
}
while(t<m)
{
while(!st.empty() && col[st.top()]) st.pop();
if (st.empty()) break;
t++;
int r=st.top(); st.pop();
col[r]=q.front();
q.pop();
}
if (pret>=m) ans+=(a[k].x-prek);
pret=t;
prek=a[k].x;
k=p;
}
printf("%d\n%d",ans,col[1]);
for (int i=2;i<=n;i++) printf(" %d",col[i]); puts("");
}
}