【CodeForces429E】Points and Segments(欧拉回路)

来源:互联网 发布:詹姆斯深蹲力量数据 编辑:程序博客网 时间:2024/05/24 01:54

题目大意

n(1n105)条线段,每条覆盖[li,ri](1li,ri109,liri)的区间,给每条线段染红色或蓝色,使得数轴上每个点(不一定是整点)的红色覆盖数与蓝色覆盖数差的绝对值小于等于1。输出任意一种染色方案。

题解

用到的欧拉回路性质

先说一说我们在本题中需要用到的一些欧拉回路的一些性质。
欧拉
(红色是从左往右走,蓝色是从右往左走)

当图的结点都在一个数轴上时,如果存在欧拉回路,
当一个点被一条边从左往右越过,或发出一条像有的边,因为存在环,所以这个点一定被另一条从右往左的边越过,或收到一条向左的边。
这样,每个点向右发出或越过的边一定等于向左接收或越过的边,利用这个性质红蓝染色,就可以解决本题。
注意:一个点接收到的向右的边,或发出的向左的边是没有计算在上述性质中的。

建图

我们需要考虑的是数轴上所有点,而不是整点。
可以发现数轴上很多点的覆盖情况是一样的,所以应该区间一段一段的考虑。
可以发现,这样的区间
区间1
与这样的区间
区间2
是没有区别的,也就是说,我们可以把右端点右移一点,没有影响。
我们甚至可以把上图的第一条线段的右端点右移到无限逼近与5,但和5中间还是有段空间。
可以把坐标5拆成51,5251是一个无限逼近与5的位置,52就是5,5152之间依然有距离。
然后把上面所说的点当做结点,将线段连边,第一条线段就是1>51连走无限次的边,每个数字的两个结点都要连边(这些边最后不染色,是无关的)。

为什么要把原本线段是[1,4]的,最后连成[1,51]呢?
因为线段[1,4]是包含4的,而前面讲的欧拉图性质是没有计算向右进入的边,如果直接连向4,相当于把4忽略掉了,所以连向5,保证了区间覆盖情况不变。
(实际上,实现时,每个数字并不需要拆成两个点,因为这两个点之间欧拉路直接带过,没有卵用,只是为了方便理解)

连好这些边后,有可能并不存在欧拉回路,因为还有很多奇点,而我们并不能随便把这些奇点连接起来,因为关于这些点的边有可能跨越了大片其它与之不连通的点,乱连会造成错误。(每条欧拉路径,没有环,都会造成一些点,覆盖的两种颜色正好差一,而欧拉路径多了,叠加后可能造成一种颜色过多,如下图,红色太多)
反例
注意到走完欧拉路径,起点和终点两个是奇点,它们这之间一定是颜色覆盖数不相等的,而其他区域都是红蓝相等。
由所以如果从一个奇点走到另一个奇点,中间如果还夹着其它奇点,就会造成中间一个区间,被多个奇点连线覆盖,导致这一区间多次缺少某一颜色。所以如果我们按顺序把相邻的奇点连在一起,就可以避免,原因:

  • 如果相邻的奇点是不同连通块,连起来后,连成一个连通块,会成为一个更大的连通块,而这个大连通块要么已经是回路(此时只有这两个奇点之间缺一颜色),要么仍有起点和终点,而起点和终点一定在这两个奇点后面了,永远无法影响此处,这里就完事了。
  • 如果相邻的奇点是同一连通块的起点和终点,连接后,以后其它的连通块也不会再影响这里。

所以,总体过程,把输入的线段右端点+1,然后离散化,然后直接连边,把相邻的奇点连边,跑欧拉路。从左往右走的路染红色,从右往左的路染蓝色。

代码

#include<cstdio>#include<algorithm>using namespace std;const int MAXN=400005;int id[MAXN*2],edge[MAXN][2];struct Edge{    int u,v,segid;    bool vis;    Edge *next,*back;}*V[MAXN*2],E[MAXN*2],*cur=E;void add_edge(int a,int b,int i){    cur->u=a;    cur->v=b;    cur->segid=i;    cur->next=V[a];    cur->back=cur+1;    V[a]=cur++;    cur->u=b;    cur->v=a;    cur->segid=i;    cur->next=V[b];    cur->back=cur-1;    V[b]=cur++;}Edge *path[MAXN*2];int pcnt;void euler(int id){    for(Edge *p=V[id];p;p=p->next)        if(!p->vis)        {            p->vis=1;            p->back->vis=1;            euler(p->v);            path[++pcnt]=p;        }}bool vis[MAXN*2];int deg[MAXN*2];int obb[MAXN*2],ocnt;bool ans[MAXN];int main(){    int n,m,l,r;    scanf("%d",&n);    for(int i=1;i<=n;i++)    {        scanf("%d%d",edge[i],edge[i]+1);        edge[i][1]++;        id[i*2-1]=edge[i][0];        id[i*2]=edge[i][1];    }    sort(id+1,id+n*2+1);    m=unique(id+1,id+n*2+1)-id-1;    for(int i=1;i<=n;i++)    {        l=lower_bound(id+1,id+m+1,edge[i][0])-id;        r=lower_bound(id+1,id+m+1,edge[i][1])-id;        add_edge(l,r,i);        deg[l]++;        deg[r]++;    }    for(int i=1;i<=m;i++)        if(deg[i]&1)            obb[++ocnt]=i;    for(int i=1;i<=ocnt;i+=2)        add_edge(obb[i],obb[i+1],0);    for(int i=1;i<=m;i++)        if(!vis[i])        {            pcnt=0;            euler(i);            vis[path[pcnt]->u]=1;            for(int j=pcnt;j>0;j--)            {                vis[path[j]->v]=1;                ans[path[j]->segid]=(path[j]->u<path[j]->v);            }        }    for(int i=1;i<n;i++)        printf("%d ",(int)ans[i]);    printf("%d\n",(int)ans[n]);    return 0;}
原创粉丝点击