CF538H Summer Dichotomy

题意

  • 有一些同学和(n)个老师,要求从中选出至少(t)个至多(T)学生分成两组
  • 要求第(i)名老师所分得的学生人数在([l_i, r_i])的范围内并且每个老师都要分到某一组去
  • 并且有一些老师不能在同一组
  • 构造一组方案

先不考虑(t, T)的限制,那么分情况考虑:

  1. 所有区间都有交集
  2. 最后答案将老师分成两个集合,且两集合交集的交集为空

对于情况1,只要在交集里面选两个点就好

对于情况2,考虑选的较小的那个点(x),可以发现这个点一定会在所有(r_i)的前面,否则另外一个点更大,那这个(r_i)就无法分组了,所以这个点一定会满足:

[xleqmin_{i=1}^{n}{r_i} ]

再考虑较大的那个点(y),同样的,这个点一定会所有(l_i)的后面,否则同样不满足题意,即:

[ygeqmax_{i=1}^n{l_i} ]

然后再考虑(t,T)的限制,同样有两种情况:

  1. (x+y<t),由于(x)只能减小,所以只能增大(y),但增大多可能会不满足区间的限制,所以尽量让(y)更小
  2. (x+y>T),同理只能最小地减小(x)

于是,我们能得到的最终的(x,y)一定能满足题意,否则就无解,之后建出二分图跑跑就好了

#include<bits/stdc++.h>
#define For(i, a, b) for(int i = (a), en = (b); i <= en; ++i)
#define Rof(i, a, b) for(int i = (a), en = (b); i >= en; --i)
#define Tra(u, i) for(int i = hd[u]; ~i; i = e[i].net)
#define cst const
#define LL long long
#define DD double
#define LD long double
#define pb push_back
#define mp make_pair
#define fir first
#define sec second
#define inf 0x3f3f3f3f
#define Inf 0x3f3f3f3f3f3f3f3f
#define eps 1e-12
#define maxn 100000
using namespace std;

int T, t, n, m, mn = inf, mx = 0, L[maxn + 5], R[maxn + 5], col[maxn + 5];

template <class T>
void read(T &x){
	char ch;
	bool ok;
	for(ok = 0, ch = getchar(); !isdigit(ch); ch = getchar()) if(ch == '-') ok = 1;
	for(x = 0; isdigit(ch); x = x * 10 + ch - '0', ch = getchar());
	if(ok) x = -x;
}

int fa[2 * maxn + 5], to[maxn + 5];
int find(int x){return fa[x] == x ? x : fa[x] = find(fa[x]);}

int main(){
	//freopen("in", "r", stdin);
	read(t); read(T); read(n); read(m);
	For(i, 1, n){
		read(L[i]); read(R[i]);
		mn = min(mn, R[i]);
		mx = max(mx, L[i]);
	}
	if(mn + mx < t) mx = t - mn;
	if(mn + mx > T) mn = T - mx;
	if(mn + mx < t || mn + mx > T || mn < 0){puts("IMPOSSIBLE"); return 0;};
	For(i, 1, 2 * n) fa[i] = i;
	For(i, 1, m){
		int u, v; read(u); read(v);
		if(find(u) == find(v)){puts("IMPOSSIBLE"); return 0;}
		fa[find(n + u)] = find(v);
		fa[find(n + v)] = find(u);
	}
	For(i, 1, n) if(find(n + i) != n + i) to[find(n + i)] = find(i);
	For(i, 1, n) L[find(i)] = max(L[find(i)], L[i]), R[find(i)] = min(R[find(i)], R[i]);
	For(i, 1, n) if(find(i) == i){
		if(L[i] > R[i]){puts("IMPOSSIBLE"); return 0;}
		if(!to[i]){
			//cout << L[i] << " " << R[i] << endl;
			if(mn >= L[i] && mn <= R[i]) col[i] = 1;
			else if(mx >= L[i] && mx <= R[i]) col[i] = 2;
			else{puts("IMPOSSIBLE"); return 0;}
		}
		else{
			if(mn >= L[i] && mn <= R[i] && mx >= L[to[i]] && mx <= R[to[i]]){
				col[i] = 1;
				col[to[i]] = 2;
			}
			else if(mn >= L[to[i]] && mn <= R[to[i]] && mx >= L[i] && mx <= R[i]){
				col[i] = 2;
				col[to[i]] = 1;
			}
			else{puts("IMPOSSIBLE"); return 0;}
		}
	}
	puts("POSSIBLE");
	printf("%d %d
", mn, mx);
	For(i, 1, n) printf("%d", col[find(i)]);
	return 0;
}
原文地址:https://www.cnblogs.com/lprdsb/p/13819024.html