先特判掉全部划分到一个集合的情况,接下来只讨论存在两个集合的。
我们取一个右端点最小的区间为
A
A
A,一个左端点最大的区间为
B
B
B(
A
A
A和
B
B
B可能相同)。
我们的限制可以分为两部分。第一部分是划分的两个集合各自人数的交非空,注意到当存在三个互不相交的区间是显然无解,否则如果存在互不相交的区间,
A
A
A和
B
B
B一定不相交,于是会分在不同集合,那么可以确定一些其他区间的分法(与
A
A
A或
B
B
B在同一集合),剩余不能确定的会和
A
A
A与
B
B
B都有交,任意划分都可以。第二部分是两个集合人数的交的最小值之和不大于
T
T
T且最大值之和不小于
t
t
t。注意到不论
A
A
A与
B
B
B是否划分到同一集合,两个集合人数交的最大值有一个是
A
A
A的右端点,最小值有一个是
B
B
B的左端点。我们按右端点从小到大排序后,实质限制是一个前缀中的区间都需要和
A
A
A在同一个集合(不然另一集合的交的最大值和会过小),最小值同理。
再加上一开始不在同一个集合的限制,我们实质上得到了若干个形如两个点是否在同一个集合的限制,建成图后变为二分图判定,容易用dfs实现。
注意有一个坑点,我们求出来的方案可能会全部划分到一个集合,需要留意实现。时间复杂度
O
(
n
+
m
)
\mathcal O(n+m)
O(n+m)。
#include <bits/stdc++.h>
#define FR first
#define SE second
#define inf 0x3f3f3f3f
using namespace std;
typedef pair<int,int> pr;
vector <pr> e[100005];
inline void addEdge(int x,int y,bool v) {
e[x].push_back(pr(y,v));
e[y].push_back(pr(x,v));
}
int col[100005];
bool v0,v1;
void dfs(int x) {
if (!col[x]) v0=1; else v1=1;
for(int i=0;i<e[x].size();i++) {
int u=e[x][i].FR,v=e[x][i].SE;
if (col[u]==-1) {
col[u]=col[x]^v;
dfs(u);
}
else if ((col[x]^col[u])!=v) {
puts("IMPOSSIBLE");
exit(0);
}
}
}
pr num[100005];
int id[100005];
bool cmp1(int x,int y) {
return num[x].FR<num[y].FR;
}
bool cmp2(int x,int y) {
return num[x].SE<num[y].SE;
}
int main() {
int lt,rt,n,m;
scanf("%d%d%d%d",<,&rt,&n,&m);
for(int i=1;i<=n;i++) {
int x,y;
scanf("%d%d",&x,&y);
num[i]=pr(x,y);
}
for(int i=1;i<=m;i++) {
int x,y;
scanf("%d%d",&x,&y);
addEdge(x,y,1);
}
if (!m) {
int l=0,r=inf;
for(int i=1;i<=n;i++) {
l=max(l,num[i].FR);
r=min(r,num[i].SE);
}
if (l<=r&&l<=rt&&r>=lt) {
puts("POSSIBLE");
printf("%d 0\n",max(l,lt));
for(int i=1;i<=n;i++) putchar('1');
printf("\n");
return 0;
}
}
for(int i=1;i<=n;i++) id[i]=i;
sort(id+1,id+n+1,cmp2);
int nr=-1,sz=0;
for(int i=1;i<=n;i++)
if (num[id[i]].FR>nr) {
sz++;
nr=num[id[i]].SE;
}
if (sz>2) {
puts("IMPOSSIBLE");
return 0;
}
int id1=1,id2=1;
for(int i=1;i<=n;i++) {
if (num[i].SE<num[id1].SE) id1=i;
if (num[i].FR>num[id2].FR) id2=i;
}
if (sz==2) {
assert(id1!=id2);
for(int i=1;i<=n;i++) {
if (num[i].FR>num[id1].SE) addEdge(id1,i,1);
if (num[i].SE<num[id2].FR) addEdge(id2,i,1);
}
}
for(int i=1;i<=n;i++) {
if (i!=id1&&num[i].SE+num[id1].SE<lt) addEdge(id1,i,0);
if (i!=id2&&num[i].FR+num[id2].FR>rt) addEdge(id2,i,0);
}
memset(col,255,sizeof(col));
for(int i=1;i<=n;i++)
if (col[i]==-1) {
if (!v0) col[i]=0; else col[i]=1;
dfs(i);
}
if (!v0||!v1) {
puts("IMPOSSIBLE");
return 0;
}
int l1=0,r1=inf,l2=0,r2=inf;
for(int i=1;i<=n;i++)
if (!col[i]) {
l1=max(l1,num[i].FR);
r1=min(r1,num[i].SE);
}
else {
l2=max(l2,num[i].FR);
r2=min(r2,num[i].SE);
}
puts("POSSIBLE");
if (l1+l2>=lt) printf("%d %d\n",l1,l2);
else if (l1+r2>=lt) printf("%d %d\n",l1,lt-l1);
else printf("%d %d\n",lt-r2,r2);
for(int i=1;i<=n;i++) putchar((!col[i])?'1':'2');
printf("\n");
return 0;
}