CodeForces - 704D Captain America

Description

坐标平面上有 \(n\) 个点,要给这些点染色,染成红色代价是 \(r\) ,染成蓝色代价是 \(b\) 。同时要满足一些条件:

  • \(1\ l \ d\)\(x = l\) 的所有点中两种颜色数量差不超过 \(d\)
  • \(2 \ l \ d\)\(y=l\) 的所有点中两种颜色数量差不超过 \(d\)

问最小代价。

\(n,m\le 10^5,1\le x,y\le 10^9\)

Solution

这种题一般是先把所有点染成代价高的,然后考虑最多有多少个点能被改成代价低的。

把每一行和每一列当成节点,对于某个点 \((x,y)\) ,就从第 \(x\) 行连向第 \(y​\) 列,表示存在这个点。对于那些限制条件就从源/汇点连带有上下界的边。

要判无解就先跑一个可行流再最大流就行了。

点数 \(2\times 10^5\) ,这题真tm信仰。

#include<bits/stdc++.h>
using namespace std;

template <class T> void read(T &x) {
	x = 0; bool flag = 0; char ch = getchar(); for (; ch < '0' || ch > '9'; ch = getchar()) flag |= ch == '-';
	for (; ch >= '0' && ch <= '9'; ch = getchar()) x = x * 10 + ch - 48; flag ? x = ~x + 1 : 0;
}

#define N 200010
#define rep(i, a, b) for (int i = (a); i <= (b); i++)
#define INF 0x3f3f3f3f

int head[N], cur[N], tot = 1, q[N], dep[N];
struct edge { int v, c, next; }e[2000010];
inline void insert(int u, int v, int c) {
	e[++tot].v = v, e[tot].c = c, e[tot].next = head[u]; head[u] = tot;
}
inline void add(int u, int v, int c) { insert(u, v, c), insert(v, u, 0); }
inline bool bfs(int S, int T) {
	memset(dep, 0, sizeof dep); dep[S] = 1;
	int l = 1, r = 1; q[1] = S;
	while (l <= r) {
		int u = q[l++];
		for (int i = head[u], v; i; i = e[i].next) if (e[i].c && !dep[v = e[i].v]) {
			dep[v] = dep[u] + 1, q[++r] = v;
			if (v == T) return 1;
		}
	}
	return 0;
}
int dfs(int u, int dist, int T) {
	if (u == T) return dist;
	int ret = 0;
	for (int &i = head[u], v; i; i = e[i].next) if (dep[v = e[i].v] == dep[u] + 1 && e[i].c) {
		int d = dfs(v, min(dist - ret, e[i].c), T);
		e[i].c -= d, e[i ^ 1].c += d, ret += d;
		if (ret == dist) return dist;
	}
	if (!ret) dep[u] = -1;
	return ret;
}

int dinic(int S, int T) {
	int ret = 0; memcpy(cur, head, sizeof head);
	while (bfs(S, T)) ret += dfs(S, INF, T), memcpy(head, cur, sizeof cur);
	return ret;
}

int x[N], y[N], a[2][N], cnt[2], sum[2][N], pos[N], mx[2][N], mn[2][N], d[N];

inline int get(int x, int y) {
	return lower_bound(a[y] + 1, a[y] + 1 + cnt[y], x) - a[y];
}

int main() {
	int n, m, r, b; read(n), read(m), read(r), read(b);
	rep(i, 1, n) read(x[i]), read(y[i]), a[0][++cnt[0]] = x[i], a[1][++cnt[1]] = y[i];
	rep(i, 0, 1) {
		sort(a[i] + 1, a[i] + 1 + cnt[i]);
		cnt[i] = unique(a[i] + 1, a[i] + 1 + cnt[i]) - a[i] - 1;
	}
	int num = cnt[0] + cnt[1], SS = num + 1, TT = SS + 1, S = TT + 1, T = S + 1;
	rep(i, 1, n) {
		sum[0][x[i] = get(x[i], 0)]++, sum[1][y[i] = get(y[i], 1)]++;
		add(x[i], y[i] + cnt[0], 1), pos[i] = tot - 1;
	}
	rep(i, 0, 1) rep(j, 1, cnt[i]) mx[i][j] = sum[i][j];
	rep(i, 1, m) {
		int t, l, d; read(t), read(l), read(d); t--;
		int l1 = get(l, t);
		if (a[t][l1] != l) continue;
		mx[t][l1] = min(mx[t][l1], (d + sum[t][l1]) / 2);
		mn[t][l1] = max(mn[t][l1], (sum[t][l1] - d + 1) / 2);
		if (mx[t][l1] < mn[t][l1]) { puts("-1"); return 0; }
	}
	rep(i, 1, cnt[0]) {
		add(SS, i, mx[0][i] - mn[0][i]);
		d[i] += mn[0][i], d[SS] -= mn[0][i];
	}
	rep(i, 1, cnt[1]) {
		add(i + cnt[0], TT, mx[1][i] - mn[1][i]);
		d[i + cnt[0]] -= mn[1][i], d[TT] += mn[1][i];
	}
	add(TT, SS, INF);
	int sum1 = 0;
	rep(i, 1, TT) if (d[i] > 0) add(S, i, d[i]), sum1 += d[i]; else add(i, T, -d[i]);
	int ans = dinic(S, T);
	if (ans ^ sum1) { puts("-1"); return 0; }
	ans = dinic(SS, TT);
	printf("%lld\n", 1ll * ans * min(r, b) + 1ll * (n - ans) * max(r, b));
	rep(i, 1, n) putchar(e[pos[i]].c ? (r < b ? 'b' : 'r') : (r < b ? 'r' : 'b'));
	return 0;
}

posted @ 2018-09-06 11:42  aziint  阅读(158)  评论(0编辑  收藏  举报
Creative Commons License
This work is licensed under a Creative Commons Attribution-NonCommercial 4.0 International License.