题解:
很巧妙的思路。
如果不考虑环的情况,那么我们可以把从起点相同的询问放在一起来操作,然后从s点开始按照字典序选边,跑一边dfs,用栈来存储当前的路径。每到一个t点的时候。回答一下<s,t>的询问,即拿出栈中第k个位置的点,这样的话,我们跑n次dfs就可以回答所有的询问了(offline操作)。
现在问题变难了,如果有环的话,字典序最小的路径有可能不存在。这就需要我们在dfs的过程中进行判环,想到使用tarjan算法。
我们每次dfs一个点u的时候,令low[u] = inf;这样的话,如果判断有dfn[u]>=low[u](含义就是出现了一个字典序小的环)那么从经由u到达的其他点的答案均为-1了。
代码:
#include <bits/stdc++.h>
using namespace std;
const int inf = 1e8;
const int maxq = 4e5+7;
const int maxn = 3001;
vector<int> edge[maxn];
struct query{int id,x,y,k;}qs[maxq];
vector<query> Q[maxn];
int res[maxq];
int n,m,q;
bool cmp(const query &q1,const query &q2){return q1.x<q2.x;}
int dfn[maxn],low[maxn],instk[maxn],stk[maxn];
int tot,top;
void dfs(int u,int ok){
dfn[u] = ++tot;
low[u] = inf;
stk[top++] = u;
instk[u] = 1;
if(ok)
for(int i = 0;i < Q[u].size();++i)
if(Q[u][i].k <= top) res[Q[u][i].id] = stk[Q[u][i].k-1];
for(int i = 0;i < edge[u].size();++i){
int v = edge[u][i];
if(!dfn[v]){
dfs(v,ok && dfn[u] < low[u]);
low[u] = min(low[v],low[u]);
}
else if(instk[v]) low[u] = min(low[u],dfn[v]);
}
instk[u] = 0;
--top;
}
int main(){
scanf("%d%d%d",&n,&m,&q);
for(int i = 0;i < m;++i){
int a,b;
scanf("%d%d",&a,&b);
edge[a].push_back(b);
}
for(int i = 1;i <= n;i++) sort(edge[i].begin(),edge[i].end());
for(int i = 0;i < q;i++){
int f,t,k;
scanf("%d%d%d",&f,&t,&k);
qs[i] = (query){i,f,t,k};
}
sort(qs,qs+q,cmp);
memset(res,-1,sizeof(res));
for(int i = 0;i < q;++i){
Q[qs[i].y].push_back(qs[i]);
if(qs[i].x != qs[i+1].x){
memset(dfn,0,sizeof(dfn));
memset(low,0,sizeof(low));
memset(instk,0,sizeof(instk));
tot = top = 0;
dfs(qs[i].x,1);
for(int t = 1;t <= n;++t) Q[t].clear();
}
}
for(int i = 0;i < q;i++) printf("%d\n",res[i]);
return 0;
}