H. Rikka with A Long Colour Palette

2018 ICPC 徐州区域赛 H Rikka with A Long Colour Palette

题目链接:http://codeforces.com/gym/102012/problem/H
在这里插入图片描述

题意

有n条线段[l,r],k种颜色,为每条线段染一种颜色,问能被k种颜色覆盖的区间的最大总长,并输出一种染色方案。
∑n<=2e6,1<=k<=2e5,0<=l<r<= 1e9。

思路

贪心+扫描线
如果某一段>=k条的线段覆盖,那么这一段一定是满足条件的,问题在于如何求染色方案。
把 n 条线段的 2 * n 个端点按位置排序,相同位置右端点更靠前 (因为右端点归还颜色要先于左端点染色),将左端点标记为1,右端点标记为-1。
用一个队列 col 存待使用的颜色,开始时存入1 ~ k。
从小到大遍历排序后的端点,

如果是左端点,并且 col 队列不为空,我们就将这个线段染成队首的颜色.

如果是左端点,并且 col 队列为空,随便染色会有后效性,于是将这条线段存入延迟染色集合set中;

如果是右端点,如果这条线段染过色,就将该颜色放入队尾,进行回收

如果是右端点,如果这条线段没被染色,那么它一定在延迟染色集合set里,没有贡献,染什么色都可以,就染成1,然后从延迟染色集合中去掉。

处理完该端点后,若 col 不空, 即覆盖的颜色不够k 种,则从set 中取出延迟染色的线段为其分配颜色,直到两者其中一个为空。

至于总长度,记录一下col 由不空变为空的位置st,由空变为不空的位置ed.
st 与 ed 之间的这段都满足要求,将 ed - st 加到 总长度 sum 里

代码

#include<bits/stdc++.h>
#define buff  std::ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
using namespace std;
typedef long long ll;
const int N=2e5+10;
int t,n,k;
struct node
{
    int x,y,pos;
} a[N];
bool cmp(node a,node b)
{
    return a.x<b.x||(a.x==b.x&&a.y<b.y);
}
bool book[N];
int ans[N];
int main()
{
    scanf("%d",&t);
    while(t--)
    {
        memset(book,false,sizeof(book));
        scanf("%d%d",&n,&k);
        for(int i=1,p=1; i<=n; i++,p+=2)
        {
            scanf("%d%d",&a[p].x,&a[p+1].x);
            a[p].pos=a[p+1].pos=i;
            a[p].y=1;
            a[p+1].y=-1;
        }
        sort(a+1,a+n*2+1,cmp);
        queue<int> col;
        set<int> wait; 
        int sum=0;
        int flag=0,st=0;
        for(int i=1; i<=k; i++)
            col.push(i);
        for(int i=1; i<=2*n; i++)
        {
            if(a[i].y==1)
            {
                if(!col.empty())
                {
                    book[a[i].pos]=1;
                    ans[a[i].pos]=col.front();
                    col.pop();
                }
                else
                {
                    wait.insert(a[i].pos);
                }
            }
            else
            {
                if(book[a[i].pos])
                {
                    col.push(ans[a[i].pos] );
                }
                else
                {
                    wait.erase(a[i].pos);
                    ans[a[i].pos]=1;
                }
            }
            while(!col.empty()&&!wait.empty())
            {
                set<int>::iterator it=wait.begin();
                book[*it]=1;
                ans[*it]=col.front();
                col.pop();
                wait.erase(*it);
            }
            if(flag==0&&col.empty())
            {
                flag=1;
                st=a[i].x;
            }
            if(flag==1&&!col.empty())
            {
                flag=0;
                sum+=(a[i].x-st);
            }
        }
        printf("%d\n",sum);
        for(int i=1; i<=n; i++)
        {
            printf("%d%c",ans[i],(i==n?'\n':' '));
        }
    }
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值