​传送门​

题目大意

给定一个 \(n\) 个点和 \(m\) 条边的无向图,每条边都有一个 \([l,r]\) 的限制,请计算出从 \(1\) 到 \(en\) 的限制范围是多少(即路径上 \(l\) 尽量小,\(r\) 尽量大)。

\(100\%\) 的数据 \(2 <= N <= 1000, 0 <= M <= 3000, 1 <= a, b <= N, 1 <= l <= r <= 10^6\)。

解题思路

考试时排序写错,惨丢 \(70pts\) 和 \(rk \ 3\)。

排序,然后枚举 \(l\),根据 \(l\) 建边,用并查集判断是否联通,最后更新答案。

AC CODE
#include <bits/stdc++.h>
using namespace std;

#define int long long

#define _ 20005

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

int mmax;

int n, m;

int ansk, ansl, ansr;

int fa[_ << 1];

int find(int x)
{
return fa[x] == x ? x : fa[x] = find(fa[x]);
}

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

struct abc
{
int u, v, l, r;
} k[_ << 1];

bool cmp(abc a, abc b)
{
if(a.r != b.r)
return a.r > b.r;
return a.l < b.l;
}

signed main()
{
n = read(), m = read();
for(int i = 1; i <= m; ++i)
{
k[i].u = read(), k[i].v = read(), k[i].l = read(), k[i].r = read();
mmax = max(mmax, max(k[i].u, k[i].v));
}
sort(k + 1, k + m + 1, cmp);
for(int i = 1; i <= m; ++i)
{
init();
int r = INT_MAX;
for(int j = 1; j <= m; ++j)
{
if(k[j].l <= k[i].l)
{
int uu = find(k[j].u), vv = find(k[j].v);
if(uu != vv)
{
fa[vv] = uu;
r = min(r, k[j].r);
if(find(1) == find(n)) break;
}
}
}
if(find(1) == find(n) && (ansk < r - k[i].l + 1 || (ansk == r - k[i].l + 1 && ansl > k[i].l)))
{
ansk = r - k[i].l + 1;
ansl = k[i].l;
ansr = r;
}
}
printf("%lld\n", ansk);
if(ansk != 0)
for(int i = ansl; i <= ansr; ++i)
printf("%lld%c", i, " \n"[i == ansr]);
return 0;
}