题目链接:
https://jzoj.net/senior/#main/show/5177
题目:
题解:
首先选出的泡泡怪一定是连续的一段 L,R
然后 L 一定属于虫洞左边界中的某一个 R 也同样是这样的
这样就可以枚举 L 和 R,$O(N)$判断是否可行(显然不可能重复经过某个点),总复杂度 $O(NM^2)$
我们看到 R<=1e6 选择二分 R 而不是枚举,这样就可以了
#include<algorithm> #include<cstring> #include<cstdio> #include<iostream> using namespace std; const int N=1e3+15; const int M=3e3+15; const int inf=1e6; int n,m,tot; int head[N],L[M],vis[N]; struct EDGE{ int to,nxt,l,r; }edge[M<<1]; inline int read(){ char ch=getchar();int s=0,f=1; while (ch<'0'||ch>'9') {if (ch=='-') f=-1;ch=getchar();} while (ch>='0'&&ch<='9') {s=(s<<3)+(s<<1)+ch-'0';ch=getchar();} return s*f; } void link(int u,int v,int l,int r){ edge[++tot]=(EDGE){v,head[u],l,r}; head[u]=tot; } bool dfs(int x,int l,int r) { if (x==n) return 1; if (vis[x]) return 0; vis[x]=1; for (int i=head[x];i;i=edge[i].nxt) { if (edge[i].l<=l&&edge[i].r>=r) { if (dfs(edge[i].to,l,r)) return 1; } } return 0; } bool check(int l,int r) { memset(vis,0,sizeof(vis)); if (dfs(1,l,r)) return 1; return 0; } int main() { n=read();m=read(); for (int i=1,u,v,l,r;i<=m;i++){ u=read();v=read();l=read();r=read(); link(u,v,l,r);link(v,u,l,r); L[i]=l; } sort(L+1,L+1+m); int ans=0,al,ar; for (int i=m;i;i--){ int l=L[i],r=inf; while (l+1<r) { int mid=l+r>>1; if (check(L[i],mid)) { if (mid-L[i]+1>=ans) { ans=mid-L[i]+1; al=L[i];ar=mid; } l=mid; } else r=mid; } } printf("%d ",ans); for (int i=al;i<=ar;i++) printf("%d ",i); return 0; }