1. 程式人生 > 實用技巧 >旅行

旅行

題面

題意

滿足兩點間路徑上所有l,r限制的最優解

題解

因為每次只能通過一個蟲洞,所以最後的答案一定是一個連續序列。

記錄l,r,爆搜是 O(n^3) 的

考慮優化,列舉每個固定的r,再二分l,檢查1,n是否連通,是 O(n^2 * log n)的

但其實不用二分每個 l ,連上就好了,O(n^2)

程式碼

 1 #include<bits/stdc++.h>
 2 #define For(i,a,b) for(register int i=(a);i<=(b);i++)
 3 #define Rof(i,a,b) for(register int i=(a);i>=(b);i--)
 4
using namespace std; 5 const int maxn=5010; 6 int n,m,head[maxn],cnt,fa[maxn],l[maxn],r[maxn],ansl,ansr; 7 struct Edge{ 8 int u,v,l,r; 9 }edge[maxn]; 10 inline bool temp(Edge a,Edge b){return a.r>b.r;} 11 inline int findfa(int x){ 12 return x==fa[x]?x:fa[x]=findfa(fa[x]); 13 } 14 inline void
uni(int a,int b){ 15 int x=findfa(a),y=findfa(b); 16 if(x!=y) fa[x]=y; 17 } 18 signed main(){ 19 scanf("%d%d",&n,&m); 20 For(i,1,m){ 21 scanf("%d%d%d%d",&edge[i].u,&edge[i].v,&edge[i].l,&edge[i].r); 22 l[i]=edge[i].l,r[i]=edge[i].r;//if(edge[i].u>edge[i].v) swap(edge[i].u,edge[i].v);
23 } 24 sort(edge+1,edge+1+m,temp),sort(l+1,l+1+m),sort(r+1,r+m+1); 25 For(i,1,m){ 26 For(j,1,m) fa[j]=j; 27 int pos=1; 28 Rof(j,m,1){ 29 if(l[i]>r[j]) break; 30 while(edge[pos].r>=r[j]){ 31 if(edge[pos].l<=l[i]) uni(edge[pos].u,edge[pos].v); 32 pos++; 33 } 34 if(findfa(1)==findfa(n)){ 35 if(r[j]-l[i]>ansr-ansl) ansl=l[i],ansr=r[j]; 36 break; 37 } 38 } 39 } 40 printf("%d\n",ansr-ansl+1); 41 For(i,ansl,ansr) printf("%d ",i); 42 }
View Code

教訓

沒試過這麼降智地調一題:l , r 打混、沒重置並查集、把迴圈條件寫成了草稿上的break條件

所以在宿舍 不能看打牌, 要睡覺