$n leq 300000$的完全无向图,每条边有可行和不可行的状态,一开始只有$m leq 300000$条边是可行的,给出。每次从$x$走到$y$时,所有与$x$相连的边的可行/不可行状态会改变。问从1最少走几步到$n$。
先考虑只走原来有的路,如果走原来有的路能到$n$,那么这可能是一种可行方案。如果要利用边状态的改变来到达$n$,最优地可以找一个距离为2的点,走到他,再回到1,然后一步到$n$,读者自证不难(考虑每一步如果会出现更优的利用原图没有的边来走会发生什么)。也就是说,直接走路程$leq4$时直接走,否则找个距离2的绕一圈。
如果没有距离2的点,又不能到$t$,那么1所在的连通分量大概是个菊花,但菊花的叶子是有连边的。这时从1走出去再也回不到1,可删之,与1相连的点变成若干连通块。新到那个点叫$x$,如果$x$的连通块里有个距离$x$为2的点,那可以用上面的方法得到5的答案;如果没有,说明这个点与分量里的所有点有连边,那还要递归下去找吗?不必了,如果枚举所有与1相连的点做如此判断,得不到5的答案就无解了。证明可以联系大前提:没有与1距离大于1的点。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 //#include<iostream> 2 #include<cstring> 3 #include<cstdio> 4 //#include<math.h> 5 //#include<set> 6 //#include<queue> 7 //#include<vector> 8 #include<algorithm> 9 #include<stdlib.h> 10 using namespace std; 11 12 #define LL long long 13 int qread() 14 { 15 char c; int s=0,f=1; while ((c=getchar())<'0' || c>'9') (c=='-') && (f=-1); 16 do s=s*10+c-'0'; while ((c=getchar())>='0' && c<='9'); return s*f; 17 } 18 19 //Pay attention to '-' , LL and double of qread!!!! 20 21 int n,m; 22 #define maxn 300011 23 struct Edge{int to,next;}edge[maxn<<1]; int first[maxn],le=2; 24 void in(int x,int y) {Edge &e=edge[le]; e.to=y; e.next=first[x]; first[x]=le++;} 25 void insert(int x,int y) {in(x,y); in(y,x);} 26 27 int dis[maxn],pre[maxn],ufs[maxn],que[maxn],head,tail,du[maxn],size[maxn]; 28 int find(int x) {return x==ufs[x]?x:(ufs[x]=find(ufs[x]));} 29 void Union(int x,int y) {if ((x=find(x))!=(y=find(y))) ufs[x]=y,size[y]+=size[x];} 30 void bfs(int s) 31 { 32 for (int i=1;i<=n;i++) dis[i]=0x3f3f3f3f,pre[i]=0; 33 head=tail=1; que[tail++]=s; dis[s]=0; 34 while (head!=tail) 35 { 36 int x=que[head++]; 37 for (int i=first[x];i;i=edge[i].next) 38 { 39 Edge &e=edge[i]; if (e.to==1) continue; 40 if (dis[e.to]==0x3f3f3f3f) 41 { 42 dis[e.to]=dis[x]+1; 43 pre[e.to]=x; 44 que[tail++]=e.to; 45 } 46 } 47 } 48 } 49 50 int main() 51 { 52 n=qread(); m=qread(); 53 for (int i=1,x,y;i<=m;i++) {x=qread(); y=qread(); insert(x,y);} 54 bfs(1); 55 if (dis[n]<=4) 56 { 57 printf("%d 1 ",dis[n]); 58 int ans[10],lans=0; 59 for (int i=n;i!=1;i=pre[i]) ans[++lans]=i; 60 for (int i=lans;i;i--) printf("%d ",ans[i]); 61 return 0; 62 } 63 for (int i=1;i<=n;i++) if (dis[i]==2) 64 { 65 printf("4 1 %d %d 1 %d",pre[i],i,n); 66 return 0; 67 } 68 for (int i=2;i<n;i++) du[i]=-1,ufs[i]=i,size[i]=1; 69 for (int i=2;i<n;i++) if (dis[i]==1) 70 for (int j=first[i];j;j=edge[j].next) 71 { 72 if (edge[j].to!=1) Union(i,edge[j].to); 73 du[i]++; 74 } 75 for (int i=2;i<n;i++) if (dis[i]==1) 76 { 77 int u=size[find(i)]; 78 if (u-1==du[i]) continue; 79 bfs(i); 80 for (int j=2;j<n;j++) if (dis[j]==2) 81 { 82 printf("5 1 %d %d %d %d %d",i,pre[j],j,i,n); 83 return 0; 84 } 85 } 86 puts("-1"); 87 return 0; 88 }