【CF827F】Dirty Arkady's Kitchen DP
阿新 • • 發佈:2018-01-30
dir break back font for etc 題解 div getc
【CF827F】Dirty Arkady‘s Kitchen
題意:給你一張n個點,m條邊的有向圖,每條邊長度為1,第i條邊在[li,ri)的時間內可以進入,求1到n的最短路。
$n,m\le 5\times 10^5$
題解:我們先將所有邊按l從小到大排序,然後依次向圖中加入每條邊。首先對於一條邊,我們可以反復走這條邊,因此不難想到將每個點按到達時間的奇偶性拆成兩個。然後每個點可以到達的時間就可以看成若幹個互不相交的區間,我們用mn[i],mx[i]維護當前最後一段區間的左右端點。
在加入一條邊時,我們先判斷當前能不能走,如果不能走我們就開個vector把每個點當前不能走的邊存起來;如果能走,則我們進行BFS,取出每個點vector中的所有邊並更新mn,mx值,如果一個點能走了就將其加入隊列,枚舉到n時更新答案即可。
#include <cstdio> #include <iostream> #include <cstring> #include <algorithm> #include <queue> #include <vector> using namespace std; const int maxn=1000010; int n,m,tot,ans; int mx[maxn],mn[maxn],fir[maxn]; struct edge { int a,b,l,r; }p[maxn<<1]; queue<int> q; vector<int> v[maxn]; inline void add(int a,int b,int c,int d) { p[++tot].a=a,p[tot].b=b,p[tot].l=c+((c^a)&1),p[tot].r=d-((d^b)&1); } bool cmp(const edge &a,const edge &b) { return a.l<b.l; } inline void solve(int x) { int a=p[x].a,b=p[x].b,l=p[x].l=max(p[x].l,mn[a]),r=p[x].r; if(mx[a]<l) { v[a].push_back(x); return ; } q.push(x); while(!q.empty()) { x=q.front(),q.pop(),a=p[x].a,b=p[x].b,l=p[x].l,r=p[x].r; if(l>=r) continue; if(mx[b]+2<l) mn[b]=l+1,mx[b]=r; else mx[b]=max(mx[b],r); if((b>>1)==n) ans=min(ans,mn[b]); while(fir[b]<(int)v[b].size()) { int t=v[b][fir[b]]; if(mx[b]>=p[t].l) fir[b]++,q.push(t),p[t].l=mn[b]; else break; } } } inline int rd() { int ret=0,f=1; char gc=getchar(); while(gc<‘0‘||gc>‘9‘) {if(gc==‘-‘) f=-f; gc=getchar();} while(gc>=‘0‘&&gc<=‘9‘) ret=ret*10+(gc^‘0‘),gc=getchar(); return ret*f; } int main() { n=rd(),m=rd(); if(n==1) { puts("0"); return 0; } int i,a,b,c,d; for(i=1;i<=m;i++) { a=rd(),b=rd(),c=rd(),d=rd(); add(a<<1,b<<1|1,c,d); add(a<<1|1,b<<1,c,d); add(b<<1,a<<1|1,c,d); add(b<<1|1,a<<1,c,d); } sort(p+1,p+tot+1,cmp); memset(mx,0xc0,sizeof(mx)),memset(mn,0xc0,sizeof(mn)); mn[2]=mx[2]=0,ans=1<<30; for(i=1;i<=tot;i++) solve(i); if(ans==(1<<30)) puts("-1"); else printf("%d",ans); return 0; }//5 4 1 2 0 10 2 3 0 10 3 4 0 10 4 5 0 10
【CF827F】Dirty Arkady's Kitchen DP