(二分图染色 + 联通块 + 线段树)
#include<bits/stdc++.h> #define inf 1e18 #define ll long long #define int long long #define ull unsigned long long #define PI acos(-1.0) #define PII pair<int,int> #define lowbit(x) (x & (-x)) using namespace std; const int N = 1e6+7, M = N * 4; int x,y,n,m; int b_vis[N]; int col[N]; int a[N][2],vis[N][2]; int h[N],nxt[M],e[M],idx; struct node{ int l,r; int v; }tr[N*4]; void pushup(int u){ tr[u].v=min(tr[u<<1].v,tr[u<<1|1].v); } void build(int u,int l,int r){ tr[u]={l,r,(ll)inf}; if(l==r) return ; int mid = l+r >>1; build(u<<1,l,mid); build(u<<1|1,mid+1,r); } // modify(1,seg[i].id,seg[i].min); void modify(int u,int x,int v){ if(tr[u].l==tr[u].r){ if(tr[u].v==inf)tr[u].v = v; else tr[u].v = max(tr[u].v,v); return ; } int mid = tr[u].l + tr[u].r >>1; if(x<=mid) modify(u<<1,x,v); else modify(u<<1|1,x,v); pushup(u); } struct bb{ int min,max,id; bool operator < (const bb &rhs)const{ return max < rhs.max; } }seg[N<<1]; void add(int u,int v){ e[++idx]=v; nxt[idx] = h[u]; h[u] = idx; } bool dfs(int u,int c){ col[u] = c; for(int i=h[u];i;i=nxt[i]){ int v= e[i]; if(col[v] == -1){ if(!dfs(v,!c)) return false; } else if(col[v]==c) return false; } return true; } void dfs2(int x,int c,int num){ vis[x][c]=1; seg[num].min=min(seg[num].min,a[x][c]); seg[num].max=max(seg[num].max,a[x][c]); for(int i=h[x];i;i=nxt[i]){ int v = e[i]; if(vis[v][c^1])continue; dfs2(v,c^1,num); } } void solve(){ scanf("%lld%lld",&n,&m); for(int i=1;i<=n;++i)h[i]=0; for(int i=1;i<=m;++i){ scanf("%lld%lld",&x,&y); add(x,y);add(y,x); } for(int i=1;i<=n;++i){ scanf("%lld%lld",&a[i][0],&a[i][1]); } int block = 0;//联通块数 //染色 判断是否存在方案 int flag=true; for(int i=0;i<=n;++i) col[i]=-1; for(int i=1;i<=n;++i) if(col[i]==-1){ if(dfs(i,0)==false) flag=false; block++; } if(flag==false){//染色失败 printf("IMPOSSIBLE "); return ; } //cout<<"ok "; for(int i=1;i<=block*2;++i){//块信息清空 seg[i].max=0;seg[i].min=inf; b_vis[i]=0; } int cnt = 0; for(int i=1;i<=n;++i) vis[i][0]=0,vis[i][1]=0;//划块路径清空 for(int i=1;i<=n;++i){ if(vis[i][0]==0){ dfs2(i,0,++cnt);//划分块 dfs2(i,1,++cnt); seg[cnt-1].id=cnt/2; seg[cnt].id=cnt/2; } } sort(seg+1,seg+1+cnt); build(1,1,block); int ans = inf; int b_cnt = 0;//更新时已用过的块 for(int i=1;i<=cnt;++i){ if(b_vis[seg[i].id]==0){ b_cnt++; b_vis[seg[i].id]=1; } //线段树修改 modify(1,seg[i].id,seg[i].min); if(b_cnt==block)ans = min (ans,seg[i].max-tr[1].v); // cout<<seg[i].max<<" == "<<tr[1].v<<" "; } printf("%lld ",ans); } signed main(){ int t=1; scanf("%lld",&t); for(int _=1;_<=t;++_){ printf("Case %lld: ",_); solve(); } return 0; }