CF864F Cities Excursions 题解

· · 题解

感觉 @Saliеri 的题解从什么意义上来说都很麻烦,我的实现应该简单一些?

题意

求一张有向图上两点间字典序最小路径的第 k 个,或判定其不存在字典序最小路径/无法到达。

## 题解 注意到 $n$ 只有 $3000$,允许我们枚举路径终点 $T$。 此时建出反图,那么从 $T$ 做一遍 dfs 即可找到所有能到达 $T$ 的点,不管字典序问题。 那么,对于每个可以到达 $T$ 的点,其在到 $T$ 的字典序最小路径上的后继节点都是唯一的,即为可以到达 $T$ 的点中字典序最小的。 我们将每个点连边其后继节点,那么会形成一颗新的树,注意到其为内向。 再将新树中的边反向,此时形成一颗外向树吗,此时再从 $T$ 点 dfs,能够访问到的点即为合法的起点 $S$。 最后,将询问离线,在第二个 dfs 时开个栈统计一下就搞定了。 点个赞吧。 ```cpp #include<bits/stdc++.h> using namespace std; int read() { int s=0,w=1; char ch=getchar(); while(ch<'0'||ch>'9') {if(ch=='-')w=-1;ch=getchar();} while(ch>='0'&&ch<='9') s=(s<<3)+(s<<1)+(ch^48),ch=getchar(); return s*w; } const int maxn = 3010; vector<int>g[maxn],z[maxn],G[maxn];char v[maxn];int Q[maxn],pr[400010],n,m,q; void add(int x,int y) {g[y].push_back(x),z[x].push_back(y);} void ADD(int x,int y) {G[x].push_back(y);} void dfs(int x) {v[x]=1;for(auto y:g[x]) if(!v[y]) dfs(y);} struct E {int s,t,k,n;};vector<E>ve[maxn],w[maxn]; void _dfs(int x) { Q[++Q[0]]=x; for(auto y:w[x]) if(Q[0]>=y.k) pr[y.n]=Q[Q[0]-y.k+1]; for(auto y:G[x]) _dfs(y);--Q[0]; } signed main() { n=read(),m=read(),q=read(); for(int i=1,x;i<=m;i++) x=read(),add(x,read()); for(int i=1;i<=n;i++) sort(z[i].begin(),z[i].end()); for(int i=1,x,y;i<=q;i++) x=read(),y=read(),ve[y].push_back((E){x,y,read(),i}),pr[i]=-1; for(int t=1;t<=n;t++) { for(int i=1;i<=n;i++) G[i].clear(),w[i].clear(),v[i]=0; v[t]=1,dfs(t); for(int i=1;i<=n;i++) if(v[i]&&i^t) for(auto y:z[i]) if(v[y]) {ADD(y,i);break;} for(auto y:ve[t]) w[y.s].push_back(y); _dfs(t); } for(int i=1;i<=q;i++) cout<<pr[i]<<'\n'; return 0; } ```