题目
T(T<=20)组样例,每组样例给定n(n<=2e5)个人,
第i个人要么加入光明阵营,获得li(1<=li<=1e9)的值,
要么加入黑暗阵营,获得di(1<=di<=1e9)的值,
m(0<=m<=2e5)个互斥关系,每次给定x,y,表示x和y不能在同一阵营中,
如果不能满足互斥关系,输出IMPOSSIBLE
否则希望n个人中能力值最大值减能力值最小值的差最小,
输出这个最小的差
题解
感觉自己就tm是乱搞的,也不知道这题正解是啥
考虑先按种类并查集合并,类似食物链那道题,
如果互斥的关系已经在相同的关系下,说明无解,
否则转化为k个连通分量,形如每个连通分量要么取121要么取212,
则在[mn[f1],mx[f1]],[mn[f2],mx[f2]]里取一个,
这里暴力讨论了两条线段的相交关系,如果线段有内含关系就只取里面那个,
否则只能是不相交或者相交,肯定一条线段在上一条在下,
考虑[mn[f2],mx[f2]]在上的情形,如果最大值<mx[f2],则最小值只能取mn[f1],
先取mn[f2]作左端点,然后nex的vector用于释放mn[f1],
枚举最大值r,注意r不能小于两个最大值中的最小值,所以是n个min(mn[f1],mn[f2])中的最大值
线段树上二分找到与其对应的最小值l,暴力更新答案即可
代码
#include <bits/stdc++.h>
using namespace std;
const int N=4e5+10;
const int INF=0x3f3f3f3f;
#define fi first
#define se second
#define pb push_back
typedef pair<int,int> P;
P a,b;
vector<int>nex[N];
int t,n,m,c,nowl,l[N],d[N],X[N],Y[N],x[N],p;
int mx[N],mn[N],par[N];
bool vis[N];
int find(int x){
return par[x]==x?x:par[x]=find(par[x]);
}
bool in(P a,P b){
return b.fi<=a.fi && a.fi<=b.se && b.fi<=a.se && a.se<=b.se;
}
void mer(int x,int y){
x=find(x),y=find(y);
if(x==y)return;
par[y]=x;
mn[x]=min(mn[x],mn[y]);
mx[x]=max(mx[x],mx[y]);
}
bool same(int x,int y){
x=find(x),y=find(y);
return x==y;
}
int main(){
scanf("%d",&t);
for(int ca=1;ca<=t;++ca){
c=0;p=0;
scanf("%d%d",&n,&m);
for(int i=1;i<=2*n;++i){
par[i]=i;
nex[i].clear();
vis[i]=0;
}
for(int i=1;i<=m;++i){
scanf("%d%d",&X[i],&Y[i]);
}
for(int i=1;i<=n;++i){
scanf("%d%d",&l[i],&d[i]);
x[++p]=l[i];x[++p]=d[i];
}
sort(x+1,x+p+1);
p=unique(x+1,x+p+1)-(x+1);
for(int i=1;i<=n;++i){
l[i]=lower_bound(x+1,x+p+1,l[i])-x;
d[i]=lower_bound(x+1,x+p+1,d[i])-x;
mx[i]=mn[i]=l[i];
mx[i+n]=mn[i+n]=d[i];
}
bool ok=1;
for(int i=1;i<=m;++i){
if(same(X[i],Y[i])){
ok=0;
break;
}
mer(X[i],Y[i]+n);
mer(X[i]+n,Y[i]);
}
printf("Case %d: ",ca);
if(!ok){
puts("IMPOSSIBLE");
continue;
}
int lim=0,nowl=INF;
for(int i=1;i<=n;++i){
int f1=find(i),f2=find(i+n);
if(vis[f1]||vis[f2])continue;
vis[f1]=vis[f2]=1;
lim=max(lim,min(mx[f1],mx[f2]));
a=P(mn[f1],mx[f1]);
b=P(mn[f2],mx[f2]);
if(in(a,b)){
nowl=min(nowl,mn[f1]);
}
else if(in(b,a)){
nowl=min(nowl,mn[f2]);
}
else{
if(mx[f2]>mx[f1])nowl=min(nowl,mn[f2]),nex[mx[f2]].pb(mn[f1]);
else nowl=min(nowl,mn[f1]),nex[mx[f1]].pb(mn[f2]);
}
}
int ans=INF;
for(int i=p;i>=lim;--i){
nowl=min(nowl,i);
ans=min(ans,x[i]-x[nowl]);
for(auto &v:nex[i]){
nowl=min(nowl,v);
}
}
printf("%d\n",ans);
}
return 0;
}