[并查集]JZOJ 5794 旅行
分析
这道题我们将r从大到小排序,然后我们知道l最后肯定停留在某个li上面,所以我们可以暴力枚举m,然后并查集判断连通性加边即可
时间复杂度O(m^2)
#pragma GCC optimize(3) #include <iostream> #include <cstdio> #include <algorithm> using namespace std; const int N=1001; struct Edge { int u,v,nx,l,r; bool operator < (const Edge &a) const {return r<a.r;} }g[3*N]; int cnt,list[N]; bool b[N]; int n,m,ansl,ans; int f[N],r[N]; inline void Add(int u,int v,int l,int r) {g[cnt].u=u;g[cnt].v=v;g[cnt].l=l;g[cnt].r=r;g[cnt].nx=list[u];list[u]=cnt++;} inline int Get_F(int x) {return x==f[x]?x:f[x]=Get_F(f[x]);} inline int Merge(int x,int y) { int i=Get_F(x),j=Get_F(y); if (r[i]<r[j]) f[i]=f[j],r[j]=max(r[j],r[i]+1); else f[j]=f[i],r[i]=max(r[i],r[j]+1); } void Solve(int lim) { for (int i=1;i<=n;i++) f[i]=i,r[i]=1; for (int i=m-1;i>=0;i--) { if (g[i].l>lim||Get_F(g[i].u)==Get_F(g[i].v)) continue; Merge(g[i].u,g[i].v); if (Get_F(1)==Get_F(n)) { if (g[i].r-lim+1>=ans) { if (g[i].r-lim+1==ans) { ansl=min(ansl,lim); } else ansl=lim; ans=g[i].r-lim+1; } return; } } } int main() { freopen("travel.in","r",stdin); freopen("travel.out","w",stdout); scanf("%d%d",&n,&m); for (int i=0;i<m;i++) { int u,v,l,r; scanf("%d%d%d%d",&u,&v,&l,&r); Add(u,v,l,r); } sort(g,g+cnt); int maxr; for (int i=0;i<m;i++) { int l=1,r=m; Solve(g[i].l); } printf("%d\n",ans); for (int i=ansl;i<=ans+ansl-1;i++) printf("%d ",i); fclose(stdin);fclose(stdout); }
在日渐沉没的世界里,我发现了你。