专栏文章

P14219 [ICPC 2024 Kunming I] 阻止城堡 2

P14219题解参与者 1已保存评论 0

文章操作

快速查看文章及其快照的属性,并进行相关操作。

当前评论
0 条
当前快照
1 份
快照标识符
@minlp0m8
此快照首次捕获于
2025/12/02 04:27
3 个月前
此快照最后确认于
2025/12/02 04:27
3 个月前
查看原文
首先删障碍不好考虑,转化为初始没有障碍,要在指定的 mkm - k 个位置加入障碍,要求中间有障碍的城堡对数最大。
发现加入一个障碍最多使得两对城堡产生贡献:横向的一对和纵向的一对。所以我们优先加入能使得两对城堡产生贡献的障碍,再加入能使得一对城堡产生贡献的障碍,最后若还有剩余就随便加入。
将横向相邻的一对城堡看做左部点,纵向相邻的一对城堡看做右部点,那么一个障碍如果能使两对城堡产生贡献,就可以在这两对城堡中连边,我们要求的就是二分图最大匹配。
然后加入能使得一对城堡产生贡献的障碍是简单的,直接模拟即可。
n,mn, m 同阶,时间复杂度 O(nlogn+nn)O(n \log n + n \sqrt n)
代码CPP
#include <bits/stdc++.h>
#define pb emplace_back
#define fst first
#define scd second
#define mkp make_pair
#define mems(a, x) memset((a), (x), sizeof(a))

using namespace std;
typedef long long ll;
typedef double db;
typedef unsigned long long ull;
typedef long double ldb;
typedef pair<int, int> pii;

const int maxn = 1000100;
const int inf = 0x3f3f3f3f;

int n, m, K, hd[maxn], nt, S, T, len, id1[maxn], id2[maxn], e[maxn];
bool vis[maxn], mk1[maxn], mk2[maxn];
pii c[maxn];

struct node {
	int x, y;
} a[maxn], b[maxn];

struct edge {
	int to, next, cap, flow;
} edges[maxn << 1];

inline void add_edge(int u, int v, int c, int f) {
	edges[++len].to = v;
	edges[len].next = hd[u];
	edges[len].cap = c;
	edges[len].flow = f;
	hd[u] = len;
}

struct Dinic {
	int cur[maxn], d[maxn];
	bool vis[maxn];
	
	inline void add(int u, int v, int c) {
		add_edge(u, v, c, 0);
		add_edge(v, u, 0, 0);
	}
	
	inline bool bfs() {
		for (int i = 1; i <= nt; ++i) {
			d[i] = -1;
			vis[i] = 0;
		}
		queue<int> q;
		q.push(S);
		vis[S] = 1;
		d[S] = 0;
		while (q.size()) {
			int u = q.front();
			q.pop();
			for (int i = hd[u]; i; i = edges[i].next) {
				edge &e = edges[i];
				if (!vis[e.to] && e.cap > e.flow) {
					vis[e.to] = 1;
					d[e.to] = d[u] + 1;
					q.push(e.to);
				}
			}
		}
		return vis[T];
	}
	
	int dfs(int u, int a) {
		if (u == T || !a) {
			return a;
		}
		int flow = 0, f;
		for (int &i = cur[u]; i; i = edges[i].next) {
			edge &e = edges[i];
			if (d[e.to] == d[u] + 1 && (f = dfs(e.to, min(a, e.cap - e.flow))) > 0) {
				e.flow += f;
				edges[i ^ 1].flow -= f;
				flow += f;
				a -= f;
				if (!a) {
					break;
				}
			}
		}
		return flow;
	}
	
	inline int solve() {
		int flow = 0;
		while (bfs()) {
			for (int i = 1; i <= nt; ++i) {
				cur[i] = hd[i];
			}
			flow += dfs(S, inf);
		}
		return flow;
	}
} solver;

void solve() {
	len = 1;
	for (int i = 0; i <= nt; ++i) {
		hd[i] = 0;
	}
	nt = 0;
	scanf("%d%d%d", &n, &m, &K);
	for (int i = 1; i <= n; ++i) {
		scanf("%d%d", &a[i].x, &a[i].y);
		id1[i] = id2[i] = 0;
		mk1[i] = mk2[i] = 0;
	}
	for (int i = 1; i <= m; ++i) {
		scanf("%d%d", &b[i].x, &b[i].y);
		vis[i] = 0;
	}
	K = m - K;
	map< int, set<pii> > mp1, mp2;
	for (int i = 1; i <= n; ++i) {
		mp1[a[i].x].emplace(a[i].y, i);
		mp2[a[i].y].emplace(a[i].x, i);
	}
	S = ++nt;
	T = ++nt;
	int ans = 0;
	for (int i = 1; i <= n; ++i) {
		auto it = mp1[a[i].x].find(pii(a[i].y, i));
		if (next(it) != mp1[a[i].x].end()) {
			id1[i] = ++nt;
			++ans;
			solver.add(S, id1[i], 1);
		}
		it = mp2[a[i].y].find(pii(a[i].x, i));
		if (next(it) != mp2[a[i].y].end()) {
			id2[i] = ++nt;
			++ans;
			solver.add(id2[i], T, 1);
		}
	}
	for (int i = 1; i <= m; ++i) {
		e[i] = 0;
		c[i] = pii(0, 0);
		if (mp1.find(b[i].x) != mp1.end()) {
			auto it = mp1[b[i].x].lower_bound(pii(b[i].y, 0));
			if (it != mp1[b[i].x].end() && it != mp1[b[i].x].begin()) {
				c[i].fst = prev(it)->scd;
			}
		}
		if (mp2.find(b[i].y) != mp2.end()) {
			auto it = mp2[b[i].y].lower_bound(pii(b[i].x, 0));
			if (it != mp2[b[i].y].end() && it != mp2[b[i].y].begin()) {
				c[i].scd = prev(it)->scd;
			}
		}
		int x = c[i].fst, y = c[i].scd;
		if (x && y) {
			solver.add(id1[x], id2[y], 1);
			e[i] = len - 1;
		}
	}
	solver.solve();
	int cnt = K;
	for (int i = 1; i <= m; ++i) {
		if (!e[i]) {
			continue;
		}
		int j = e[i];
		if (edges[j].flow) {
			if (cnt) {
				--cnt;
				ans -= 2;
				vis[i] = 1;
				mk1[c[i].fst] = mk2[c[i].scd] = 1;
			}
		}
	}
	for (int i = 1; i <= m; ++i) {
		if (vis[i]) {
			continue;
		}
		if (cnt && ((c[i].fst && !mk1[c[i].fst]) || (c[i].scd && !mk2[c[i].scd]))) {
			--cnt;
			--ans;
			vis[i] = 1;
			if (c[i].fst) {
				mk1[c[i].fst] = 1;
			}
			if (c[i].scd) {
				mk2[c[i].scd] = 1;
			}
		}
	}
	for (int i = 1; i <= m; ++i) {
		if (!vis[i] && cnt) {
			--cnt;
			vis[i] = 1;
		}
	}
	printf("%d\n", ans);
	for (int i = 1; i <= m; ++i) {
		if (vis[i]) {
			continue;
		}
		printf("%d ", i);
	}
	putchar('\n');
}

int main() {
	int T = 1;
	scanf("%d", &T);
	while (T--) {
		solve();
	}
	return 0;
}

评论

0 条评论,欢迎与作者交流。

正在加载评论...