题意:
有n个人,每个人有两个权值L(i)和R(i),
每个人要么选择L要么选择R,
但是现在m对关系,每对关系的两个人不能选择同一方,
问每个人选择之后,所有人的权值最大值与最小值的差值最小是多少?
如果关系出现冲突,无法进行选择则输出Impossible。
数据范围:n,m<=2e5
解法:
二分图染色,如果染色冲突则无解,
否则每个连通块只有两种选择,记录每种选择的mi和ma,以及连通块的id
对所有选择按最大值ma从小到大排序,
设一共有num个连通块
枚举最大值ma,线段树T维护当前枚举左边的所有连通块的最小值.
当前面以及存在num个连通块时,则可以用ma-T.mi更新答案.
code:
#include<bits/stdc++.h>
using namespace std;
const int maxm=4e5+5;
vector<int>g[maxm];
int l[maxm],r[maxm];
struct Node{
int mi,ma,id;
}e[maxm];
int mark[maxm];
int c[maxm];
int ok,tot;
int n,m;
struct Tree{
int a[maxm<<2];
inline void pp(int node){//pushup
a[node]=min(a[node*2],a[node*2+1]);
}
void build(int l,int r,int node){//清空
if(l==r){
a[node]=1e9;
return ;
}
int mid=(l+r)/2;
build(l,mid,node*2);
build(mid+1,r,node*2+1);
pp(node);
}
void update(int x,int val,int l,int r,int node){//单点修改
if(l==r){
a[node]=val;
return ;
}
int mid=(l+r)/2;
if(x<=mid)update(x,val,l,mid,node*2);
else update(x,val,mid+1,r,node*2+1);
pp(node);
}
int ask(int x,int l,int r,int node){//单点查询
if(l==r)return a[node];
int mid=(l+r)/2;
if(x<=mid)return ask(x,l,mid,node*2);
else return ask(x,mid+1,r,node*2+1);
}
}T;
void dfs(int x,int col){//二分图染色
if(!ok)return ;
c[x]=col;
if(col==1){
e[tot].mi=min(e[tot].mi,l[x]);
e[tot].ma=max(e[tot].ma,l[x]);
e[tot-1].mi=min(e[tot-1].mi,r[x]);
e[tot-1].ma=max(e[tot-1].ma,r[x]);
}else{
e[tot].mi=min(e[tot].mi,r[x]);
e[tot].ma=max(e[tot].ma,r[x]);
e[tot-1].mi=min(e[tot-1].mi,l[x]);
e[tot-1].ma=max(e[tot-1].ma,l[x]);
}
for(int v:g[x]){
if(c[v]==-1)dfs(v,!col);
else if(c[v]==c[x])ok=0;
}
}
bool cmp(Node a,Node b){
return a.ma<b.ma;
}
signed main(){
int TT;scanf("%d",&TT);
int cas=1;
while(TT--){
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)g[i].clear();
for(int i=1;i<=m;i++){
int a,b;scanf("%d%d",&a,&b);
g[a].push_back(b);
g[b].push_back(a);
}
for(int i=1;i<=n;i++){
scanf("%d%d",&l[i],&r[i]);
}
//
for(int i=1;i<=n;i++)c[i]=-1;
ok=1,tot=0;
int num=0;
for(int i=1;i<=n&&ok;i++){
if(c[i]==-1){
num++;
e[++tot]={(int)1e9,(int)-1e9,num};
e[++tot]={(int)1e9,(int)-1e9,num};
dfs(i,1);
}
}
//
printf("Case %d: ",cas++);
if(!ok){
puts("IMPOSSIBLE");
continue;
}
//
sort(e+1,e+1+tot,cmp);
T.build(1,num,1);
for(int i=1;i<=num;i++)mark[i]=0;
int sum=0;
int ans=1e9;
for(int i=1;i<=tot;i++){
if(e[i].ma<0)continue;
if(!mark[e[i].id]){
mark[e[i].id]=1;
sum++;
}
int temp=T.ask(e[i].id,1,num,1);
if(sum==num){
T.update(e[i].id,e[i].mi,1,num,1);
ans=min(ans,e[i].ma-T.a[1]);
}
if(temp==1e9)temp=e[i].mi;
else temp=max(temp,e[i].mi);
T.update(e[i].id,temp,1,num,1);
}
printf("%d\n",ans);
}
return 0;
}