Description
有 n n n堂讲课, m m m次研讨会, x x x个高清投影仪和 y y y个普通投影仪。
每堂讲课必须使用一个高清投影仪,而研讨会可以使用普通或高清投影仪。
第 i i i堂讲课时间在 [ a i , b i ) [a_i,b_i) [ai,bi),第 i i i次研讨会在时间在 [ p i , q i ) [p_i,q_i) [pi,qi),一个投影仪一次只能用在一个地方,且在使用完毕后才会归还。
构造为每节讲课/研讨会分配一个投影仪的方案。
n , m , x , y ≤ 300 , a i , b i , p i , q i ≤ 1 0 6 n,m,x,y \leq 300, a_i,b_i,p_i,q_i \leq 10^6 n,m,x,y≤300,ai,bi,pi,qi≤106
Solution
考虑已经知道了普通投影仪如何分配,那么存在分配高清投影仪的合法方案的充要条件是,对于任意整数 t t t,时刻 t + 0.5 t+0.5 t+0.5满足需要用到的投影仪数量不超过 x + y x+y x+y。
那么这意味着,我们只关心每个时刻到底要用多少投影仪,而不关心他们具体是什么。这启发我们想到网络流, 1 1 1单位流量代表普通投影仪在每个时刻的状态。考虑每个时刻最多有多少普通投影仪是空闲的,显然是 m i n ( x , x + y − s u m ) min(x,x+y-sum) min(x,x+y−sum),其中 s u m sum sum是这个时刻所需要的投影仪,即此时至少有 y − m i n ( x , x + y − s u m ) y-min(x,x+y-sum) y−min(x,x+y−sum)台投影仪被使用。
- 建立一个时间轴,上面的节点依次表示时刻 0 , 1 , . . . , i , . . . 0,1,...,i,... 0,1,...,i,...。 i + 0.5 i+0.5 i+0.5向 i + 1.5 i+1.5 i+1.5连流量为 m i n ( x , x + y − s u m ) min(x,x+y-sum) min(x,x+y−sum)的边,其中 s u m sum sum是时刻 i + 0.5 i+0.5 i+0.5所需要的投影仪。时间轴上的流量表示空闲。
- 对于研讨会 i i i,连边 p i → q i p_i\to q_i pi→qi,流量为 1 1 1。表示这个投影仪此时被次研讨会使用。
存在合法解的方案当且仅当 0 0 0到 I n f Inf Inf的流量为 y y y。
如何构造方案?考虑跑完最大流后,每次从 t t t向 s s s退 1 1 1流量,如果一次研讨会使用当前的投影仪,当前仅当这个研讨会所代表的边被这个流量经过。
分配高清投影仪贪心即可。总时间复杂度 O ( T ( n + m ) 2 ) O(T(n+m)^2) O(T(n+m)2)
tips: 需要把时间离散保证复杂度。
#include <bits/stdc++.h>
using namespace std;
const int maxn = 605, Inf = 1 << 30;
inline int gi()
{
char c = getchar();
while (c < '0' || c > '9') c = getchar();
int sum = 0;
while ('0' <= c && c <= '9') sum = sum * 10 + c - 48, c = getchar();
return sum;
}
int n, m, A, B, x[maxn], y[maxn], *q[maxn << 1], ti;
int vis[maxn], now[maxn], ans[maxn], sum[maxn << 1], Id[maxn];
vector<int> vec[maxn << 1];
struct edge
{
int to, next, cap;
} e[maxn * 5];
int h[maxn << 1], cur[maxn << 1], dis[maxn << 1], tot;
inline void add(int u, int v, int w)
{
//printf("%d %d %d\n", u, v, w);
e[++tot] = (edge) {v, h[u], w}; h[u] = tot;
e[++tot] = (edge) {u, h[v], 0}; h[v] = tot;
}
bool bfs(int s, int t, int E)
{
static int u, l, r, q[maxn << 1];
memset(dis + 1, 0, sizeof(int) * ti);
l = 0; q[r = 1] = s; dis[s] = 1;
while (l < r) {
u = q[++l];
for (int i = h[u], v; v = e[i].to, i; i = e[i].next)
if ((i & 1) != E && !dis[v] && e[i].cap) dis[v] = dis[u] + 1, q[++r] = v;
}
return dis[t];
}
int dfs(int u, int t, int a, int E)
{
if (u == t || !a) return a;
int flow = 0, f;
for (int &i = cur[u], v; v = e[i].to, i; i = e[i].next)
if ((i & 1) != E && dis[v] == dis[u] + 1 && (f = dfs(v, t, min(a, e[i].cap), E))) {
a -= f; flow += f;
e[i].cap -= f; e[i ^ 1].cap += f;
if (!a) break;
}
return flow;
}
int max_flow(int s, int t, int f, int E)
{
int res = 0;
while (bfs(s, t, E) && res < f) {
memcpy(cur + 1, h + 1, sizeof(int) * ti);
res += dfs(s, t, f, E);
}
return res;
}
int main()
{
freopen("arrange20.in", "r", stdin);
freopen("B.out", "w", stdout);
int T = gi();
while (T--) {
n = gi(); m = gi(); A = gi(); B = gi();
int Min = -1e9, Max = 1e9 + 1;
q[tot = 1] = &Min; q[++tot] = &Max;
for (int i = 1; i <= n; ++i) x[i] = gi(), y[i] = gi(), q[++tot] = x + i, q[++tot] = y + i;
for (int i = 1; i <= m; ++i) x[n + i] = gi(), y[n + i] = gi(), q[++tot] = x + n + i, q[++tot] = y + n + i;
sort(q + 1, q + tot + 1, [](int *a, int *b) {return *a < *b;});
ti = 0;
for (int lst = -1, i = 1; i <= tot; ++i) {
if (*q[i] == lst) *q[i] = ti;
else lst = *q[i], *q[i] = ++ti;
}
memset(sum + 1, 0, sizeof(int) * ti);
for (int i = 1; i <= n + m; ++i)
for (int j = x[i]; j < y[i]; ++j) ++sum[j];
tot = 1; memset(h + 1, -1, sizeof(int) * ti);
bool flg = 1;
for (int i = 1; i < ti; ++i) {
if (A + B < sum[i]) {flg = 0; break;}
add(i, i + 1, min(B, A + B - sum[i]));
}
if (!flg) {puts("NO"); continue;}
for (int i = n + 1; i <= n + m; ++i) add(x[i], y[i], 1), Id[i - n] = tot;
if (max_flow(1, ti, Inf, -1) != B) puts("NO");
else {
puts("YES");
memset(vis + 1, 0, sizeof(int) * m);
memset(ans + 1, 0, sizeof(int) * (n + m));
for (int i = 1; i <= m; ++i) vis[i] = !e[Id[i]].cap;
for (int i = 1; i <= B; ++i) {
max_flow(ti, 1, 1, 0);
for (int j = 1; j <= m; ++j)
if (!vis[j] && !e[Id[j]].cap) vis[j] = 1, ans[n + j] = A + i;
}
for (int i = 1; i <= ti; ++i) vec[i].clear();
for (int i = 1; i <= n + m; ++i) if (!ans[i]) vec[x[i]].push_back(i);
memset(now + 1, 0, sizeof(int) * A);
for (int i = 1; i <= ti; ++i)
for (int t : vec[i])
for (int j = 1; j <= A; ++j)
if (y[now[j]] <= x[t]) {now[j] = t; ans[t] = j; break;}
for (int i = 1; i <= n; ++i) printf("%d ", ans[i]), assert(ans[i]);
puts("");
for (int i = 1; i <= m; ++i) printf("%d ", ans[n + i]), assert(ans[n + i]);
puts("");
}
}
return 0;
}