CF429E Points and Segments 题解
一个很简单的做法,不需要欧拉回路或者二分图什么的图论知识,而且好写。
虽然题解满了,还是记录一下。
首先,因为样例没有无解的情况,猜测一定有解。
把线段按照左端点从小到大排序。如果第一条与第二条无交,第一条就随便染了。我们讨论有交的情况。
前两条线段必然异色。因为存在一个只包含前两条线段的区域 —— 如果不存在,那么我们可以人为在第二、三个左端点之间加入一段区域,这样只会让限制更强,但因为我们猜测了任何情况都有解,所以这一步转化后仍然有解。
然后此时把前两条线段绑在一起,发现这一个整体对于后续只会在
还有点小问题,就是原题意说的是数轴上任意一点,但是实际上只看整点也是没有问题的,因为线段的端点都是整数,有交的话必然会有整点在交里面。主要方便代码实现。
Upd: 只关注整点是错的,虽然 CF 数据没有卡。给所有端点乘
需要一个左端点的小根堆,时间复杂度
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=100010;
int fa[N],d[N];
int get(int x){
if(!fa[x])return x;
int r=get(fa[x]);
if(r!=fa[x]){
d[x]^=d[fa[x]];
}
return fa[x]=r;
}
int n,l[N],r[N];
signed main(){
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
cin>>n;
for(int i=1;i<=n;i++)cin>>l[i]>>r[i],l[i]*=2,r[i]*=2;
priority_queue<pair<int,int>,vector<pair<int,int>>,greater<pair<int,int>>>q;
for(int i=1;i<=n;i++)q.push({l[i],i});
while(q.size()>1){
int x=q.top().second;q.pop();
int y=q.top().second;q.pop();
if(r[x]<l[y]){
q.push({l[y],y});
continue;
}
if(r[x]<r[y]){
fa[x]=y,d[x]=1;
l[y]=r[x]+1;
if(l[y]<=r[y]){
q.push({l[y],y});
}
}
else{
fa[y]=x,d[y]=1;
l[x]=r[y]+1;
if(l[x]<=r[x]){
q.push({l[x],x});
}
}
}
for(int i=1;i<=n;i++){
get(i);
cout<<d[i]<<' ';
}
}