[codeforces827F] Dirty Arkady's Kitchen

题目大意给定n个点m条无向边,边权为1.每条边还有一个出现时间区间。从1出发,每个时刻必须沿着一条边走到另一个点。问你最早什么时候到达n。无解输出-1 n,m≤500000分析我们不妨把每个点拆成两个点,表示时刻为奇数和偶数。 边也按照奇偶拆开,再拆成两条有向边。 然后用小根堆以加入时间为关键字维护每条边。设Late[u][p]表示当前奇偶性为p的点u,最晚可以逗留到什么时候。加入一条边时,如
摘要由CSDN通过智能技术生成

题目大意

给定n个点m条无向边,边权为1.每条边还有一个出现时间区间。从1出发,每个时刻必须沿着一条边走到另一个点。问你最早什么时候到达n。无解输出-1
n,m≤500000

分析

我们不妨把每个点拆成两个点,表示时刻为奇数和偶数。
边也按照奇偶拆开,再拆成两条有向边。
然后用小根堆以加入时间为关键字维护每条边。设Late[u][p]表示当前奇偶性为p的点u,最晚可以逗留到什么时候。加入一条边时,如果它的起点Late大于等于它的出现时间,那么这条边是可达的,然后去更新终点的答案。否则把它存在起点,等待这个点下一次被访问时再拿出来。
可以发现拆出来的每条边最多访问两次,所以时间复杂度是 O(mlogm)

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>

using namespace std;

const int N=5e5+5,M=N<<2;

typedef long long LL;

int n,m,Late[N][2],tot,H[N][2],nxt[M];

struct Data
{
    int u,v,l,r;
}tmp,e[M];

priority_queue <Data> h;

bool operator < (Data a,Data b)
{
    return a.l>b.l;
}

char c;

int read()
{
    int x=0,sig=1;
    for (c=getchar();c<'0' || c>'9';c=getchar()) if (c=='-') sig=-1;
    for (;c>='0' && c<='9';c=getchar()) x=x*10+c-48;
    return x*sig;
}

void Add(Data t)
{
    e[++tot]=t; nxt[tot]=H[t.u][t.l&1]; H[t.u][t.l&1]=tot;
}

void Extend(int x,int t,int en)
{
    Late[x][t&1]=max(Late[x][t&1],en);
    for (int i=H[x][t&1];i;i=nxt[i])
    {
        tmp=e[i]; tmp.l=t;
        h.push(tmp);
    }
    H[x][t&1]=0;
}

int main()
{
    n=read(); m=read();
    if (n==1)
    {
        printf("0\n"); return 0;
    }
    for (int a,b,l,r,i=1;i<=m;i++)
    {
        a=read(); b=read(); l=read(); r=read()-1;
        tmp.u=a; tmp.v=b; tmp.l=l; tmp.r=r-((r^l)&1); h.push(tmp);
        tmp.l++; tmp.r=r-((r^l^1)&1); h.push(tmp);
        swap(tmp.u,tmp.v); tmp.l=l; tmp.r=r-((r^l)&1); h.push(tmp);
        tmp.l++; tmp.r=r-((r^l^1)&1); h.push(tmp);
    }
    memset(Late,255,sizeof(Late));
    Late[1][0]=0;
    for (;!h.empty();)
    {
        tmp=h.top(); h.pop();
        if (tmp.l>tmp.r) continue;
        if (Late[tmp.u][tmp.l&1]>=tmp.l)
        {
            if (tmp.v==n)
            {
                printf("%d\n",tmp.l+1); return 0;
            }
            Extend(tmp.v,tmp.l+1,tmp.r+1);
        }else Add(tmp);
    }
    printf("-1\n");
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值