如果我们把题目里的边连出来以后出现了奇环就一定无解,否则我们对于每个连通块,先黑白染色,然后把同色的区间求交,合并成一个区间(如果是一个孤立点就加入 ([-infty,+infty]) 作为这个和孤立点区间对立的区间),把得到的两个区间放在一个二元组里.现在相当于有若干个区间二元组 (([l1,r1],[l2,r2])),然后要决定二元组里每个区间的分别染成黑白,要使得存在两个数 (n1,n2),满足 (tle n1+n2le T),且 (n1) 被所有黑区间包含, (n2) 被所有白区间包含
上述限制条件可以改为:黑白染色后得到黑区间的交为 ([pl,pr]),白区间的交为 ([ql,qr]),要满足 ([pl+ql,pr+qr]) 和 ([t,T]) 区间有交.可以发现所有二元组里的区间最大左端点 (zl) 一定为 (pl) 或 (ql) 中的一个,区间最小右端点 (zr) 一定为 (pr) 或 (qr) 中的一个,那么我们找到最大左端点和最小右端点所在二元组,并枚举最大左端点和最小右端点对应的区间是否同色,那么这时可以先把这两个(或一个)二元组的染色情况确定下来,然后去确定其他二元组的染色.后面默认最大左端点对应区间是黑色的
由于我们先确定了全局的最大左端点和最小右端点,那如果把最大左端点对应的交区间和后面的区间求交,那么只有交区间的右端点会变小,同理最小右端点对应的颜色的交区间只有左端点会变大.现在就从小到大枚举白色对应交区间的左端点 (l_0),这时左端点比当前枚举值更小的二元组里的区间都可以被染成白色.再考虑另一个没确定的右端点(即和最小右端点对应区间不同色的交区间的右端点) (r_0) ,因为这时相当于 (pl+ql) 已确定,那么显然这个 (r_0) 是越大越好.对于其他二元组,如果有一个区间可以染白,那么另一个区间的右端点就要去限制 (r_0) 大小,如果两个两个区间都可以被染白,那么选择右端点更大的区间去限制那个 (r_0) 更优.所以这里可以用 (mathrm{multiset}) 来维护其他二元组的用来限制 (r_0) 的右端点,然后取最小值作为 (r_0).如果所有其他二元组都存在可以染白的区间,那就可以用当前的 (l_0,r_0) 和最大左端点 (zl) ,最小右端点 (zr) 作为 ([pl,pr],[ql,qr]),这时满足限制条件就可以输出答案
注意 (l_0) 要和 还没染色时的黑色交区间左端点 取 max,(r_0) 同理,以及要构造合法的 (n_1,n_2)
#include<bits/stdc++.h>
#define LL long long
using namespace std;
const int N=2e5+10;
int rd()
{
int x=0,w=1;char ch=0;
while(ch<'0'||ch>'9'){if(ch=='-') w=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+(ch^48);ch=getchar();}
return x*w;
}
int to[N<<1],nt[N<<1],hd[N],tot=1;
void adde(int x,int y)
{
++tot,to[tot]=y,nt[tot]=hd[x],hd[x]=tot;
++tot,to[tot]=x,nt[tot]=hd[y],hd[y]=tot;
}
int sl,sr,n,m,ra[N][2],a[N][2],tt=1,ff[N],co[N],sq[N],tp,cn[N];
bool an[N];
queue<int> q;
bool cmp(int aa,int bb){return a[aa][0]<a[bb][0];}
multiset<int> sb;
int main()
{
sl=rd(),sr=rd(),n=rd(),m=rd();
for(int i=1;i<=n;++i) ra[i][0]=rd(),ra[i][1]=rd();
a[0][0]=-1,a[0][1]=2e9;
for(int i=1;i<=m;++i) adde(rd(),rd());
for(int i=1;i<=n;++i)
if(!ff[i])
{
++tt,a[tt][0]=a[0][0],a[tt][1]=a[0][1];
++tt,a[tt][0]=a[0][0],a[tt][1]=a[0][1];
ff[i]=tt-1,q.push(i);
while(!q.empty())
{
int x=q.front();
q.pop();
int xt=tt^1^co[x];
a[xt][0]=max(a[xt][0],ra[x][0]),a[xt][1]=min(a[xt][1],ra[x][1]);
for(int j=hd[x];j;j=nt[j])
{
int y=to[j];
if(ff[y])
{
if(co[x]==co[y]){puts("IMPOSSIBLE");return 0;}
}
else ff[y]=ff[x]^1,co[y]=co[x]^1,q.push(y);
}
}
if(a[tt-1][0]>a[tt-1][1]||a[tt][0]>a[tt][1]){puts("IMPOSSIBLE");return 0;}
}
int m1=0,m2=0;
for(int i=2;i<=tt;++i)
{
if(a[i][0]>a[m1][0]) m1=i;
if(a[i][1]<a[m2][1]) m2=i;
}
if(a[m1][0]<=a[m2][1])
{
int z1=a[m1][0],z2=a[m2][1],pl=max(max(a[m1^1][0],a[m2^1][0]),0),pr=min(a[m1^1][1],a[m2^1][1]),rs=(tt>>1)-2+((m1>>1)==(m2>>1));
an[m1>>1]=m1&1,an[m2>>1]=m2&1;
for(int i=2;i<=tt;++i)
if((i>>1)!=(m1>>1)&&(i>>1)!=(m2>>1)) sq[++tp]=i;
sort(sq+1,sq+tp+1,cmp);
sb.insert(pr);
for(int i=0;i<=tp;++i)
{
int x=sq[i];
if(x)
{
if(a[x][0]>pr) break;
++cn[x>>1];
if(cn[x>>1]==1) --rs,sb.insert(a[x][1]),an[x>>1]=(x&1)^1;
else
{
int y=x^1;
if(a[x][1]>a[y][1])
sb.erase(sb.find(a[y][1])),sb.insert(a[x][1]),an[x>>1]^=1;
}
}
int nl=max(pl,a[x][0]),nr=(*sb.begin());
if(rs<=0&&nl<=nr&&max(nl+z1,sl)<=min(nr+z2,sr))
{
puts("POSSIBLE");
int mm=sl-(z1+nl);
if(mm>0)
{
if(z1+mm<=z2) z1+=mm;
else nl+=mm-(z2-z1),z1=z2;
}
printf("%d %d
",z1,nl);
for(int i=1;i<=n;++i) printf("%d",1+((an[ff[i]>>1]^ff[i])&1));
return 0;
}
}
}
tp=0;
sb.clear();
memset(cn,0,sizeof(cn));
if(m1!=m2)
{
int z1=a[m1][0],z2=a[m2][1],pl=max(max(a[m1^1][0],a[m2][0]),0),pr=min(a[m1][1],a[m2^1][1]),rs=(tt>>1)-2+((m1>>1)==(m2>>1));
an[m1>>1]=m1&1,an[m2>>1]=(m2&1)^1;
for(int i=2;i<=tt;++i)
if((i>>1)!=(m1>>1)&&(i>>1)!=(m2>>1)) sq[++tp]=i;
sort(sq+1,sq+tp+1,cmp);
sb.insert(pr);
for(int i=0;i<=tp;++i)
{
int x=sq[i];
if(x)
{
if(a[x][0]>z2) break;
++cn[x>>1];
if(cn[x>>1]==1) --rs,sb.insert(a[x^1][1]),an[x>>1]=(x&1)^1;
else
{
int y=x^1;
if(a[y][1]>a[x][1])
sb.erase(sb.find(a[x][1])),sb.insert(a[y][1]),an[x>>1]^=1;
}
}
int nl=max(pl,a[x][0]),nr=(*sb.begin());
if(rs<=0&&z1<=nr&&nl<=z2&&max(nl+z1,sl)<=min(nr+z2,sr))
{
puts("POSSIBLE");
int mm=sl-(z1+nl);
if(mm>0)
{
if(z1+mm<=nr) z1+=mm;
else nl+=mm-(nr-z1),z1=nr;
}
printf("%d %d
",z1,nl);
for(int i=1;i<=n;++i) printf("%d",1+((an[ff[i]>>1]^ff[i])&1));
return 0;
}
}
}
puts("IMPOSSIBLE");
return 0;
}