P3652 csh和zzy的战争

给定一些货源地,一些中转岛,以及一个终点。

货源地分为两种,普通货和特殊货。

对于中转岛 ii ,最多可以中转 wiw_i 件货物,中转岛发向另一个中转岛或军事基地的货物分别不能超过 did_i

上面货物皆指普通货物,特殊货物不会受到限制。

中转岛之间有 ee 条航道,航道 ii 有边权,开辟航线 uvu-v 的代价是 uuvv 之间的最短路。

最后全局的代价是航线代价的最大值。

要求在所有货物都能够到达军事基地的前提下,最小代价是多少。

std

首先考虑二分最小代价 gg,将代价 g\leq g 的航线加入图中,判断是否能将所有货物都送达军事基地即可。

然后考虑特殊货物,只需要先用 dij 求出每个特殊货源地到终点的最短路,然后二分下界即是每个特殊货源地到终点的最短路的最大值。

再考虑普通货物,先 O(n3)\mathcal O(n^3) 求出两点之间最短路,然后建图跑网络流即可。

1.19s / 26.07MB / 4.13KB C++20 O2\text{1.19s / 26.07MB / 4.13KB C++20 O2}

#include <bits/stdc++.h>

using namespace std;

inline int read()
{
	int x = 0, f = 1;
	char c = getchar();
	while (c < '0' || c > '9')
	{
		if (c == '-')
			f = -1;
		c = getchar();
	}
	while (c >= '0' && c <= '9')
	{
		x = x * 10 + c - '0';
		c = getchar();
	}
	return x * f;
}

inline void write(int x)
{
	if (x < 0)
	{
		putchar('-');
		x = -x;
	}
	if (x > 9)
		write(x / 10);
	putchar(x % 10 + '0');
}

typedef int tp;

const int _ = 5e5 + 10, inf = 1e9 + 7;

int n, m, s, t, lv[_], cur[_];

int tot = 1, head[_], to[_ << 1], nxt[_ << 1];

tp w[_ << 1];

inline void add(int u, int v, tp lv)
{
	to[++tot] = v;
	nxt[tot] = head[u];
	w[tot] = lv;
	head[u] = tot;
}

inline void Add(int u, int v, tp lv)
{
	add(u, v, lv);
	add(v, u, 0);
}

inline bool bfs()
{
	memset(lv, -1, sizeof(lv));
	lv[s] = 0;
	memcpy(cur, head, sizeof(head));
	queue<int> q;
	q.push(s);
	while (!q.empty())
	{
		int p = q.front();
		q.pop();
		for (int eg = head[p]; eg; eg = nxt[eg])
		{
			int v = to[eg];
			tp vol = w[eg];
			if (vol > 0 && lv[v] == -1)
				lv[v] = lv[p] + 1, q.push(v);
		}
	}
	return lv[t] != -1;
}

tp dfs(int p = s, tp flow = inf)
{
	if (p == t)
		return flow;
	tp rmn = flow;
	for (int eg = cur[p]; eg && rmn; eg = nxt[eg])
	{
		cur[p] = eg;
		int v = to[eg];
		tp vol = w[eg];
		if (vol > 0 && lv[v] == lv[p] + 1)
		{
			tp c = dfs(v, min(vol, rmn));
			rmn -= c;
			w[eg] -= c;
			w[eg ^ 1] += c;
		}
	}
	return flow - rmn;
}

inline tp dinic()
{
	tp ans = 0;
	while (bfs())
		ans += dfs();
	return ans;
}

struct node
{
	int u, v, w;
} ed[_];

bool cmp(node a, node b)
{
	return a.w < b.w;
}

int X, E, M, a[_], ww[_], b[_], d[_], dis[_], mp[507][507];

vector<int> g[307];

bool check(int lit)
{
	tot = 1;
	memset(head, 0, sizeof head);
	int sum = 0;
	for (int i = 1; i <= n; i++)
		Add(s, i, a[i]), sum += a[i];
	for (int i = 1; i <= m; i++)
	{
		if (b[i])
			Add(i + n + m, t, d[i]);
		Add(i + n, i + n + m, ww[i]);
		for (auto j : g[i])
			if (j <= n)
				Add(j, i + n, inf);
	}
	for (int i = 1; i <= M && ed[i].w <= lit; i++)
	{
		Add(ed[i].u + n + m, ed[i].v + n, d[ed[i].u]);
		Add(ed[i].v + n + m, ed[i].u + n, d[ed[i].v]);
	}
	return !(sum - dinic());
}

struct abc
{
	int u, val;
	bool operator < (const abc tmp) const
	{
		return tmp.val < val;
	}
};

void dij(int u)
{
	priority_queue<abc> q;
	q.push({u, 0});
	for(int i = 0; i < _; ++i) dis[i] = inf, lv[i] = 0;
	dis[u] = 0;
	while(!q.empty())
	{
		abc tmp = q.top();
		int now = tmp.u;
		q.pop();
		if(lv[now]) continue;
		lv[now] = 1;
		for(int i = head[now]; i; i = nxt[i])
		{
			int v = to[i];
			if(dis[v] > dis[now] + w[i])
			{
				dis[v] = dis[now] + w[i];
				if(!lv[v]) q.push({v, dis[v]});
			}
		}
	}
}

signed main()
{
	int x, y, z;
	n = read(), m = read(), X = read(), E = read();
	for (int i = 1; i <= n + X; i++)
		a[i] = read();
	for (int i = 1; i <= m; i++)
		ww[i] = read();
	for (int i = 1; i <= m; i++)
		d[i] = read();
	for (int i = 1; i <= m; i++)
	{
		x = read();
		for (int j = 1; j <= x; j++)
		{
			y = read();
			g[i].push_back(y);
			add(n + X + i, y, 0);
		}
		b[i] = read();
		if (b[i])
			add(n + X + m + 1, n + X + i, 0);
	}
	for (int i = 1; i <= E; i++)
	{
		x = read(), y = read(), z = read();
		mp[x][y] += z, mp[y][x] += z;
	}
	for (int i = 1; i <= m; i++)
		for (int j = 1; j <= m; j++)
			if (!mp[i][j])
				mp[i][j] = inf;
			else if (i != j)
				add(n + X + i, n + X + j, mp[i][j]);
	for (int k = 1; k <= m; k++)
		for (int i = 1; i <= m; i++)
			for (int j = 1; j <= m; j++)
				mp[i][j] = min(mp[i][j], mp[i][k] + mp[k][j]);
	dij(n + m + X + 1);
	s = 0, t = _ - 1;
	for (int i = 1; i <= m; i++)
		for (int j = i + 1; j <= m; j++)
			if (mp[i][j] < inf)
				ed[++M] = (node){i, j, mp[i][j]};
	sort(ed + 1, ed + M + 1, cmp);
	int l = 0, r = inf, mid;
	for (int i = n + 1; i <= n + X; i++)
		l = max(l, lv[i]);
	while (l <= r)
	{
		mid = l + r >> 1;
		if (check(mid))
			r = mid - 1;
		else
			l = mid + 1;
	}
	if (r != inf)
		write(r + 1);
	else
		write(-1);
	return 0;
}
posted @ 2022-02-25 14:14  蒟蒻orz  阅读(5)  评论(0编辑  收藏  举报  来源