欢迎访问 生活随笔!

生活随笔

当前位置: 首页 > 编程资源 > 编程问答 >内容正文

编程问答

CF827F-Dirty Arkady‘s Kitchen【堆】

发布时间:2023/12/3 编程问答 67 豆豆
生活随笔 收集整理的这篇文章主要介绍了 CF827F-Dirty Arkady‘s Kitchen【堆】 小编觉得挺不错的,现在分享给大家,帮大家做个参考.

正题

题目链接:https://www.luogu.com.cn/problem/CF827F


题目大意

给出nnn个点mmm条边的一张无向图,每条边只有在时刻[li,ri)[l_i,r_i)[li,ri)时候才能通过,且通过时间为111,你不能在一个点处停留,求111走到nnn的最短时间。

1≤n,m≤5×1051\leq n,m\leq 5\times 10^51n,m5×105


解题思路

如果能停留的话显然我们可以停留等待一条边开启,储存最短距离肯定最优。

但是现在不能停留,考虑在一条边处反复横跳,而这样我们如果要保证最优吧一个点拆成一个奇点和一个偶点,但是现在的问题是我们反复横跳的边是可能关闭的。

考虑把边的lil_ili从小到大排序来进行考虑,当我们枚举到一条边时iii如果能够到大那么下界显然没有问题(也就是能够在lll之前到达),那么考虑上界的限制,也就是我们至少需要反复横跳到时间lll才能走这条边。

fif_ifi表示目前能够到达iii的最晚时间,那么当l≤fil\leq f_ilfi的时候可以直接走这条边,否则我们需要等到以后再走这个点的fi≥lf_i\geq lfil的时候就可以了,所以我们可以把这条边先挂在xxx上然后当我们下次有一条边能够走到xxx时考虑如何处理挂在xxx上的边。

记挂在xxx上的边为AAA,走到xxx的边为BBB,因为是AAA先枚举的显然有Al≤BlA_l\leq B_lAlBl,同样的就有Br≤AlB_r\leq A_lBrAl,所以在BBB处反复横跳一定能走AAA,所以我们可以把所有挂在xxx上的边取下来然后把相等于能够新走的边加入即可。

再开一个维护目前的边即可。

时间复杂度:O(mlog⁡m)O(m\log m)O(mlogm)


code

#include<cstdio> #include<cstring> #include<algorithm> #include<queue> #include<vector> #define ll long long using namespace std; const ll N=1e6+10; struct node{ll x,y,l,r; }; ll n,m,f[N]; bool operator<(node x,node y) {return x.l>y.l;} priority_queue<node> q; vector<node> e[N]; signed main() {scanf("%lld%lld",&n,&m);if(n==1)return puts("0")&0; for(ll i=1;i<=m;i++){ll x,y,l,r;scanf("%lld%lld%lld%lld",&x,&y,&l,&r);r--;q.push((node){x,y+n,l+(l&1),r-(r&1)});q.push((node){y,x+n,l+(l&1),r-(r&1)});q.push((node){x+n,y,l+!(l&1),r-!(r&1)});q.push((node){y+n,x,l+!(l&1),r-!(r&1)});}memset(f,0xcf,sizeof(f));f[1]=0;while(!q.empty()){node x=q.top();q.pop();if(x.l>x.r)continue;if(x.l>f[x.x]){e[x.x].push_back(x);continue;}if(x.y==n||x.y==2*n)return printf("%lld\n",x.l+1)&0;f[x.y]=max(f[x.y],x.r+1);for(ll i=0;i<e[x.y].size();i++){node y=e[x.y][i];y.l=x.l+1;q.push(y);}e[x.y].clear();}puts("-1");return 0; }

总结

以上是生活随笔为你收集整理的CF827F-Dirty Arkady‘s Kitchen【堆】的全部内容,希望文章能够帮你解决所遇到的问题。

如果觉得生活随笔网站内容还不错,欢迎将生活随笔推荐给好友。