星星之火

[jzoj 5177] [NOIP2017提高组模拟6.28] TRAVEL 解题报告 (二分)

题目链接:

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\n",ans);
    for (int i=al;i<=ar;i++) printf("%d ",i);
    return 0;
}

 

posted @ 2018-11-01 20:15  星星之火OIer  阅读(170)  评论(0编辑  收藏  举报