【题解】CF366D

\(\text{Description}\)

CF366D Dima and Trap Graph

在一张无向图上有 \(N\) 个点和 \(M\) 条边,每条边连接着点 \(a\) 和点 \(b\),有无数个人编号为 \(1,2,\dots,+\infty\)。通过某条边是要一定的条件的,对于每条边,有两个值 \(l\)\(r\),表示该条边只允许编号在 \([l,r]\) 区间内的人通过,从 \(1\) 号点到达 \(N\) 号点,请求出最多有多少人可以通过,并求出这些人的编号(若有多组解取字典序最小的一组 )

  • 可能有重边和自环。
  • 如果没有人能通过只要输出 Nice work, Dima! 就可以了。
  • 对于 \(30\%\) 的数据,\(1\le N,M\le10\)
  • 对于 \(100\%\) 的数据,\(2\le N\le1000,0\le M\le3000,1\le a,b\le N,1\le l\le r\le10^6\)

\(\text{Solution}\)

有两种思路(注意字典序最小的判断):

\(1.\) 最长路

遍历每一条边,对于第 \(i\) 条边,选取边权 \(\ge l_i\) 的边,从 \(1\)\(N\) 跑最长路,让 \(r\) 最大,在 \(l\) 固定的情况下,肯定是 \(r\) 越大越好。

时间复杂度 \(\mathcal{O}(M\cdot M\log N)=\mathcal{O}(M^2\log N)\)

\(2.\) 并查集

同样是遍历每一条边 \(i\),将所有满足 \(l_j\le l_i\)\(j\),都把 \(a_j\)\(b_j\) 并入一个集合。

那么最终的 \(l\) 一定是 \(l_i\),所以把所有的 \(r_i\) 取个 \(\min\) 作为最终的 \(r\),当点 \(1\) 和点 \(N\) 在同一个集合内说明可以尝试去更新答案。

因为是并查集实现,结合路径压缩和按秩合并可以做到 \(\mathcal{O}(M^2\alpha(N))\),不过因为 \(N\le1000\) 所以优化不大,主要优化在于常数(

时间复杂度 \(\mathcal{O}(M^2\alpha(N))\)

\(\text{Code}\)

\(1.\)

#include <iostream>
#include <cstdio>
#include <queue>
#include <cstring>
using namespace std;

const int MAXN = 1005;
const int MAXM = 3005;
const int INF = 0x3f3f3f3f;

int cnt;
int head[MAXN];

struct edge
{
	int to, l, r, nxt;
}e[MAXM << 1];

void add(int u, int v, int l, int r)
{
	e[++cnt] = edge{v, l, r, head[u]};
	head[u] = cnt;
}

int dis[MAXN];
bool vis[MAXN];

struct node
{
	int u, r;
	bool operator <(const node &x)const
	{
		if (x.r == r)
		{
			return x.u < u;
		}
		return x.r > r;
	}
};

void init()
{
	memset(dis, -INF, sizeof(dis));
	memset(vis, false, sizeof(vis));
}

void dijkstra(int l)
{
	init();
	dis[1] = INF;
	priority_queue<node> pq;
	pq.push(node{1, dis[1]});
	while (!pq.empty())
	{
		int u = pq.top().u;
		pq.pop();
		if (vis[u])
		{
			continue;
		}
		vis[u] = true;
		for (int i = head[u]; i; i = e[i].nxt)
		{
			if (e[i].l > l) //取在区间内的
			{
				continue;
			}
			int v = e[i].to;
			if (dis[v] < min(dis[u], e[i].r)) //r要取min
			{
				dis[v] = min(dis[u], e[i].r);
				pq.push(node{v, dis[v]});
			}
		}
	}
}

int l[MAXM], r[MAXM];

int main()
{
	int n, m;
	scanf("%d%d", &n, &m);
	for (int i = 1; i <= m; i++)
	{
		int u, v;
		scanf("%d%d%d%d", &u, &v, l + i, r + i);
		add(u, v, l[i], r[i]);
		add(v, u, l[i], r[i]);
	}
	int ansk = 0, ansl = 0, ansr = 0;
	for (int i = 1; i <= m; i++)
	{
		dijkstra(l[i]);
		int res = dis[n] - l[i] + 1;
		if (ansk < res || (ansk == res && ansl > l[i]))
		{
			ansk = res;
			ansl = l[i];
			ansr = dis[n];
		}
	}
	if (ansk)
	{
		printf("%d\n", ansk);
		for (int i = ansl; i <= ansr; i++)
		{
			printf("%d ", i);
		}
	}
	else
	{
		puts("Nice work, Dima!");
	}
	return 0;
}

\(2.\)

#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;

const int MAXN = 1005;
const int MAXM = 3005;
const int INF = 0x3f3f3f3f;

struct edge
{
	int u, v, l, r;
}e[MAXM];

bool cmp(edge x, edge y)
{
	if (x.r == y.r)
	{
		return x.l < y.l;
	}
	return x.r > y.r;
}

int n, m, r, ansk, ansl, ansr;
int fa[MAXN], siz[MAXN];

void init()
{
	for (int i = 1; i <= n; i++)
	{
		fa[i] = i;
		siz[i] = 1;
	}
}

int find(int x)
{
	if (x == fa[x])
	{
		return x;
	}
	return fa[x] = find(fa[x]); //路径压缩
}

int main()
{
	scanf("%d%d", &n, &m);
	for (int i = 1; i <= m; i++)
	{
		scanf("%d%d%d%d", &e[i].u, &e[i].v, &e[i].l, &e[i].r);
	}
	sort(e + 1, e + m + 1, cmp);
	for (int i = 1; i <= m; i++)
	{
		init();
		r = INF;
		for (int j = 1; j <= m; j++)
		{
			if (e[j].l <= e[i].l)
			{
				int x = find(e[j].u), y = find(e[j].v);
				if (x != y)
				{
					if (siz[x] > siz[y]) //按秩合并
					{
						fa[y] = x;
						siz[x] += siz[y];
					}
					else
					{
						fa[x] = y;
						siz[y] += siz[x];
					}
					r = min(r, e[j].r);
					if (find(1) == find(n))
					{
						break;
					}
				}
			}
		}
		if (find(1) == find(n) && (ansk < r - e[i].l + 1 || (ansk == r - e[i].l + 1 && ansl > e[i].l)))
		{
			ansk = r - e[i].l + 1;
			ansl = e[i].l;
			ansr = r;
		}
	}
	if (ansk)
	{
		printf("%d\n", ansk);
		for (int i = ansl; i <= ansr; i++)
		{
			printf("%d ", i);
		}
	}
	else
	{
		puts("0");
	}
	return 0;
}
posted @ 2021-10-05 13:38  mango09  阅读(24)  评论(0编辑  收藏  举报
-->