POI2010MOS-Bridges

POI #Year2010 #二分 #Dinic #欧拉回路

看到最小值,具有单调性,考虑二分

对于一个 \(mid\)

  • 如果一条边两个方向都不能走,那么必然不合法
  • 如果只有一个方向可走,那么变为有向边
  • 否则为无向边

考虑有向图欧拉回路存在的充要条件,需要这个图中每个点的 \(indeg=outdeg=\frac{deg}{2}\)

即等价于询问是否存在一种给无向边定向的方式满足上述条件

这个可以网络流做,即对于每条边每个点分别建点,通过流量就可以限制每条边贡献 \(1\),且每个点满足流量为 \(\frac{deg}{2}\),即跑完以后检查是否满流

然后就可以确定每条边的方向,最后求欧拉回路即可

// Author: xiaruize
const int MOD = 1000000007;
const int N = 2e5 + 10;

struct MF
{
	struct edge
	{
		int v, nxt, cap, flow;
	} e[N];

	int fir[N], cnt = 0;

	int n, S, T;
	int maxflow = 0;
	int dep[N], cur[N];

	void init()
	{
		// cerr << "flag" << endl;
		maxflow = 0;
		memset(fir, -1, sizeof(fir));
		cnt = 0;
	}

	void addedge(int u, int v, int w)
	{
		e[cnt] = {v, fir[u], w, 0};
		fir[u] = cnt++;
		e[cnt] = {u, fir[v], 0, 0};
		fir[v] = cnt++;
	}

	bool bfs()
	{
		queue<int> q;
		memset(dep, 0, sizeof(int) * (n + 1));

		dep[S] = 1;
		q.push(S);
		while (q.size())
		{
			int u = q.front();
			q.pop();
			for (int i = fir[u]; ~i; i = e[i].nxt)
			{
				int v = e[i].v;
				if ((!dep[v]) && (e[i].cap > e[i].flow))
				{
					dep[v] = dep[u] + 1;
					q.push(v);
				}
			}
		}
		return dep[T];
	}

	int dfs(int u, int flow)
	{
		if ((u == T) || (!flow))
			return flow;

		int ret = 0;
		for (int &i = cur[u]; ~i; i = e[i].nxt)
		{
			int v = e[i].v, d;
			if ((dep[v] == dep[u] + 1) && (d = dfs(v, min(flow - ret, e[i].cap - e[i].flow))))
			{
				ret += d;
				e[i].flow += d;
				e[i ^ 1].flow -= d;
				if (ret == flow)
					return ret;
			}
		}
		return ret;
	}

	void dinic()
	{
		while (bfs())
		{
			memcpy(cur, fir, sizeof(int) * (n + 1));
			maxflow += dfs(S, INF);
			// cerr << maxflow << endl;
		}
	}
} mf;

int deg[N];
struct edge
{
	int u, v, l, p;
} s[N];
int n, m;
vector<pii> g[N];
int cnt[N];
stack<int> st;

bool check(int x)
{
	debug(x);
	mf.init();
	mf.S = 0;
	mf.T = mf.n = n + m + 1;
	int sum = 0;
	rep(i, 1, n)
	{
		mf.addedge(i, n + m + 1, deg[i] / 2);
		sum += deg[i] / 2;
	}
	rep(i, 1, m)
	{
		mf.addedge(0, n + i, 1);
		if (s[i].l > x && s[i].p > x)
			return false;
		if (s[i].l <= x)
			mf.addedge(n + i, s[i].v, 1);
		if (s[i].p <= x)
			mf.addedge(n + i, s[i].u, 1);
	}
	mf.dinic();
	return mf.maxflow == sum;
}

void dfs(int x, int pid)
{
	// debug(x, pid);
	for (int &i = cnt[x]; i < g[x].size();)
	{
		auto [v, id] = g[x][i++];
		dfs(v, id);
	}
	if (pid)
		st.push(pid);
}

void solve()
{
	cin >> n >> m;
	int l = INF, r = 0;
	rep(i, 1, m)
	{
		cin >> s[i].u >> s[i].v >> s[i].l >> s[i].p;
		l = min({l, s[i].l, s[i].p});
		r = max({r, s[i].l, s[i].p});
		deg[s[i].u]++;
		deg[s[i].v]++;
	}
	rep(i, 1, n) if (deg[i] & 1)
	{
		cout << "NIE";
		return;
	}
	while (l < r)
	{
		int mid = l + r >> 1;
		if (check(mid))
			r = mid;
		else
			l = mid + 1;
	}
	cout << r << endl;
}

#ifndef ONLINE_JUDGE
bool end_of_memory_use;
#endif

signed main()
{
	// freopen(".in","r",stdin);
	// freopen(".out","w",stdout);
	ios::sync_with_stdio(false);
	cin.tie(0);
	cout.tie(0);
	int testcase = 1;
	// cin >> testcase;
	while (testcase--)
		solve();
#ifndef ONLINE_JUDGE
	cerr << "Memory use:" << (&end_of_memory_use - &start_of_memory_use) / 1024.0 / 1024.0 << "MiB" << endl;
	cerr << "Time use:" << (double)clock() / CLOCKS_PER_SEC * 1000.0 << "ms" << endl;
#endif
	return 0;
}
posted @ 2024-04-18 09:02  xiaruize  阅读(5)  评论(0)    收藏  举报