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