CodeForces 786E ALT

Description

\(n\) 个点的树, \(m\) 个工人。每个工人要从 \(u_i\) 走到 \(v_i\) ,要满足该路径上每条边都有一条狗,或者让这个工人携带一条狗,问最少需要多少狗。

\(2\le n\le 2\times 10^4,1\le m\le 10^4\)

Solution

最小割。

显然的建图是 \(S\) 向每个工人连流量 \(1\) 的边,每条边向 \(T\) 连流量 \(1\) 边,每个工人向他的边连 \(+ \infty\) 的边。

这样就完蛋了,边太多无法信仰。

于是就树链剖分线段树优化建边。

说实话挺难写的。

#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;
}

//#pragma GCC diagnostic error "-std=c++14"

#define N 20010
#define M 10010
#define rep(i, a, b) for (auto i = (a); i <= (b); i++)
#define drp(i, a, b) for (auto i = (a); i >= (b); i--)
#define ll long long
#define INF 0x3f3f3f3f

#define nd N * 2 + M
int head[nd], cur[nd], tot = 1, q[nd], dep[nd];
struct edge { int v, c, next; }e[5000010];
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;
}

bool vis[nd];
void getVis(int u) {
	vis[u] = 1;
	for (int i = head[u]; i; i = e[i].next) if (e[i].c && !vis[e[i].v]) getVis(e[i].v);
}

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;
}

#define pii pair<int, int>
list<pii> g[N];

int fa[N], siz[N], val[N], dep2[N], bl[N], son[N], dfn[N], pos[N];
void dfs(int u) {
	siz[u] = 1;
	for (pii i : g[u]) {
		int v = i.first, id = i.second;
		if (v == fa[u]) continue;
		val[v] = id, dep2[v] = dep2[u] + 1, fa[v] = u, dfs(v), siz[u] += siz[v];
		if (siz[v] > siz[son[u]]) son[u] = v;
	}
}

void dfs(int u, int top) {
	bl[u] = top;
	static int ind; dfn[u] = ++ind, pos[ind] = val[u];
	if (son[u]) dfs(son[u], top);
	for (pii i : g[u]) {
		int v = i.first;
		if (v == fa[u] || v == son[u]) continue;
		dfs(v, v);
	}
}

int S, T;

int a[M], b[N];

int ndCnt, root;
struct Node { int ls, rs; }tr[N << 1];
#define mid (l + r >> 1)
void build(int& rt, int l, int r) {
	if (!rt) rt = ++ndCnt;
	if (l == r) {
		add(rt, T, 1), b[pos[l]] = rt;
		return;
	}
	build(tr[rt].ls, l, mid), build(tr[rt].rs, mid + 1, r);
	add(rt, tr[rt].ls, INF), add(rt, tr[rt].rs, INF);
}

void query(int rt, int l, int r, int L, int R, int v) {
	if (L <= l && r <= R) { add(v, rt, INF); return; }
	if (L <= mid) query(tr[rt].ls, l, mid, L, R, v);
	if (R > mid) query(tr[rt].rs, mid + 1, r, L, R, v);
}

list<int> ans1, ans2;

int main() {
	int n, m; read(n), read(m);
	rep(i, 1, n - 1) {
		int u, v; read(u), read(v);
		g[u].push_back(pii(v, i)), g[v].push_back(pii(u, i));
	}
	dfs(1), dfs(1, 1);
	S = 1, T = 2, ndCnt = 2;
	build(root, 1, n);
	rep(i, 1, m) {
		a[i] = ndCnt + i;
		add(S, ndCnt + i, 1);
		int u, v; read(u), read(v);
		while (bl[u] ^ bl[v]) {
			if (dep2[bl[u]] < dep2[bl[v]]) swap(u, v);
			query(root, 1, n, dfn[bl[u]], dfn[u], i + ndCnt), u = fa[bl[u]];
		}
		if (dep2[u] > dep2[v]) swap(u, v);
		query(root, 1, n, dfn[son[u]], dfn[v], i + ndCnt);
	}
	printf("%d\n", dinic(S, T));
	getVis(S);
	rep(i, 1, m) if (!vis[a[i]]) ans1.push_back(i);
	rep(i, 1, n) if (vis[b[i]]) ans2.push_back(i);
	printf("%d ", ans1.size()); for (int x : ans1) printf("%d ", x); puts("");	
	printf("%d ", ans2.size()); for (int x : ans2) printf("%d ", x); puts("");	
	return 0;
}
posted @ 2018-09-21 17:20  aziint  阅读(174)  评论(0编辑  收藏  举报
Creative Commons License
This work is licensed under a Creative Commons Attribution-NonCommercial 4.0 International License.