题目大意
有 n(1≤n≤105) 条线段,每条覆盖 [li,ri](1≤li,ri≤109,li和ri是整数) 的区间,给每条线段染红色或蓝色,使得数轴上每个点(不一定是整点)的红色覆盖数与蓝色覆盖数差的绝对值小于等于1。输出任意一种染色方案。
题解
用到的欧拉回路性质
先说一说我们在本题中需要用到的一些欧拉回路的一些性质。
(红色是从左往右走,蓝色是从右往左走)
当图的结点都在一个数轴上时,如果存在欧拉回路,
当一个点被一条边从左往右越过,或发出一条像有的边,因为存在环,所以这个点一定被另一条从右往左的边越过,或收到一条向左的边。
这样,每个点向右发出或越过的边一定等于向左接收或越过的边,利用这个性质红蓝染色,就可以解决本题。
注意:一个点接收到的向右的边,或发出的向左的边是没有计算在上述性质中的。
建图
我们需要考虑的是数轴上所有点,而不是整点。
可以发现数轴上很多点的覆盖情况是一样的,所以应该区间一段一段的考虑。
可以发现,这样的区间
与这样的区间
是没有区别的,也就是说,我们可以把右端点右移一点,没有影响。
我们甚至可以把上图的第一条线段的右端点右移到无限逼近与5,但和5中间还是有段空间。
可以把坐标5拆成
51,52
,
51
是一个无限逼近与5的位置,
52
就是5,
51
与
52
之间依然有距离。
然后把上面所说的点当做结点,将线段连边,第一条线段就是
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;
}