题目链接:http://codeforces.com/gym/102055/problem/B
题意: 有两个种类, n个物品, 有m句话每句话都会说明那两个不是一个种类,且每个物品被当作每个种类的价值不一样。
问是否有案例成立,若成立求出案例中物品最大的价值与最小价值之差最小。
思路: 首先用染色法求是否成立。 然后缩点把每个连通块缩点,每个点就有两种方案,每个方案都有一个最大值和最小值,然后遍历从小到大的最大值,求可成立的最大的最小值。求最小值的时候可以用线段树维护即可。
ac代码:
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <iostream>
#include <string>
#include <cstring>
#include <queue>
#include <map>
#include <iterator>
#include <vector>
#define lc d<<1
#define rc d<<1|1
#define mid ((l+r)>>1)
using namespace std;
//typedef long long ll;
//template<class T> T maxx(T a, T b) {
// return max(a, b);
//}
//template<class T, class ...R> T maxx(T a, R... b) {
// return max(a, maxx(b...));
//}
//template<class T> T minn(T a, T b) {
// return min(a, b);
//}
//template<class T, class ...R> T minn(T a, R... b) {
// return min(a, minn(b...));
//}
const int mx = 2e5+5;
const int INF = 0x3f3f3f3f;
const int mod = 1e9+7;
int head[mx];
struct edge {
int v, nex;
}E[2*mx];
int si;
void add(int u, int v) {
E[si].v = v, E[si].nex = head[u];
head[u] = si++;
}
//vector<int>ve[mx];
int cr[mx], a[2][mx];
int ma[mx][2], mi[mx][2];
struct noa {
int id, a, fa;
bool operator<(const noa &t) {
return a<t.a;
}
} N[2*mx];
//namespace T {
// const int mx =4e5+5;
struct tree {
int mi;
tree() {}
tree(int mm):mi(mm) {}
tree operator+(const tree &t) {
return tree(min(t.mi, mi));
}
} T[mx*4];
void pushup(int d) {///向上传
T[d] = T[lc] + T[rc];
}
void build(int l, int r, int d) {///建树
if (l == r) {
T[d].mi = 0;
return;
}
build(l, mid, lc);
build(mid + 1, r, rc);
pushup(d);
}
tree Query(int l, int r, int d, int x) {
if (l == r)
return T[d];
if (mid < x)
return Query(mid+1, r, rc, x);
return Query(l, mid, lc, x);
}
void update(int l, int r, int d, int L, int x) {
if (l == r) {
T[d].mi = x;
return;
}
if (mid < L)
update(mid+1, r, rc, L, x);
else
update(l, mid, lc, L, x);
pushup(d);
return;
}
bool f;
int tot;
struct que{
int fa, u, c;
que() {}
que(int ff, int uu, int cc):fa(ff), u(uu), c(cc) {}
}Q[mx+5];
inline void dfs(int fa, int u, int c) {
if (f) return;
int he = 0, fi = 0;
Q[fi++] = que(fa, u, c);
while (he < fi) {
fa = Q[he].fa, u = Q[he].u, c = Q[he].c;
he++;
ma[tot][0] = max(ma[tot][0], a[c][u]);
ma[tot][1] = max(ma[tot][1], a[c^1][u]);
mi[tot][0] = min(mi[tot][0], a[c][u]);
mi[tot][1] = min(mi[tot][1], a[c^1][u]);
cr[u] = c;
for (int i = head[u]; ~i; i = E[i].nex) {
int v = E[i].v;
// if (v == fa)
// continue;
if (cr[v] != -1 && cr[v] == c) {
f = 1;
return;
}
// dfs(u, v, c^1);
if(cr[v] == -1)
Q[fi++] = que(u, v, c^1);
}
}
return;
}
void init(int n) {
for (int i = 0; i <= n; ++i) {
head[i] = -1;
cr[i] = -1;
}
si = 0;
}
//using namespace T;
int main() {
int n, m, q, k;
int u, v;
int i;
scanf("%d", &q);
for (int o = 1; o <= q; ++o) {
printf("Case %d: ", o);
scanf("%d%d", &n, &m);
init(n);
for (i = 0; i < m; ++i) {
scanf("%d%d", &u, &v);
add(u, v);
add(v, u);
}
for (i = 1; i <= n; ++i)
scanf("%d%d", &a[0][i], &a[1][i]);
int ts = 0, mk = 0;
tot = 0;
f = 0;
for (i = 1; i <= n; ++i) {
if (cr[i] == -1) {
++tot;
ma[tot][0] = ma[tot][1] = 0;
mi[tot][0] = mi[tot][1] = INF;
dfs(i, i, 0);
mk = max(mk, min(ma[tot][0], ma[tot][1]));
N[ts].fa = 0;
N[ts].a = ma[tot][0];
N[ts++].id = tot;
N[ts].fa = 1;
N[ts].a = ma[tot][1];
N[ts++].id = tot;
}
if (f)break;
}
if (f) {
puts("IMPOSSIBLE");
continue;
}
build(1, tot, 1);
sort(N, N+ts);
int mix = INF;
tree kx;
for (i = 0; i < ts; ++i) {
kx =Query(1, tot, 1, N[i].id);
if (kx.mi < mi[N[i].id][N[i].fa]) {
update(1, tot, 1, N[i].id, mi[N[i].id][N[i].fa]);
}
if (N[i].a < mk)
continue;
update(1, tot, 1, N[i].id, mi[N[i].id][N[i].fa]);
mix = min(mix, N[i].a-T[1].mi);
if (kx.mi > mi[N[i].id][N[i].fa])
update(1, tot, 1, N[i].id, kx.mi);
}
printf("%d\n", mix);
}
return 0;
}