题意
题意: 给定一个有向图,询问由s到t的字典序最小的路径的第k个点 输入: 第一行三个整数n(2<=n<=3000),m(0<=m<=3000),q(1<=q<=400000) 接下来m行每行两个整数x,y(1<=x,y<=n且x≠y)表示由x到y有一条路(由城市x到y最多只有一条路) 接下来q行每行三个整数s,t(1<=s,t<=n且s≠t),k(1<=k<=3000) 输出: q行,每行对应一个答案 若s与t不连通输出-1 若字典序最小的路径构成环输出-1
分析
考虑只有一个询问的话,你每一次从x走到一个那些能到达y的点中的最小的一个
这个东西显然可以倍增处理,如果在环上,则走n个点后还能走,puts(“-1”)就好了
对于询问离线,枚举每个y,反着bfs一次,然后对于每个询问正着倍增
时间复杂度
O(nmlogn+qlogn)
O
(
n
m
l
o
g
n
+
q
l
o
g
n
)
代码
#include <bits/stdc++.h>
#define ll long long
#define pb push_back
using namespace std;
const int N = 3010;
inline int read()
{
char ch=getchar(); int p=0; int f=1;
while(ch<'0' || ch>'9'){if(ch=='-') f=-1; ch=getchar();}
while(ch>='0' && ch<='9'){p=p*10+ch-'0'; ch=getchar();}
return p*f;
}
struct node{int x,y,next;}edge[N]; int len,first[N];
void ins(int x,int y){len++; edge[len].x=x; edge[len].y=y; edge[len].next=first[x]; first[x]=len;}
struct node1{int x,y,k,id;}p[400010]; int fa[N][13];
int n,m,q; vector<int>v[N],g[N];
queue<int> Q; bool vis[N];
void bfs(int x)
{
while(!Q.empty()) Q.pop(); Q.push(x);
memset(vis,0,sizeof(vis)); vis[x]=1;
memset(fa,63,sizeof(fa)); fa[x][0]=0;
while(!Q.empty())
{
x=Q.front();
for(auto i:g[x])
{
if(!vis[i]){vis[i]=1; fa[i][0] = x; Q.push(i);}
else fa[i][0] = min(fa[i][0] , x);
}
Q.pop();
}
}
int ans[400010];
int main()
{
n=read(); m=read(); q=read();
len=0; memset(first,-1,sizeof(first));
for(int i=1;i<=m;i++){int x=read(); int y=read(); ins(x,y); g[y].pb(x);}
for(int i=1;i<=q;i++) p[i].x=read(),p[i].y=read(),p[i].k=read(),v[p[i].y].pb(i),p[i].id=i;
for(int y=1;y<=n;y++)
{
bfs(y);
for(int j=1;j<=12;j++) for(int x=1;x<=n;x++) if(fa[x][j-1] <= n && fa[fa[x][j-1]][j-1] <= n) fa[x][j] = fa[fa[x][j-1]][j-1];
for(auto i:v[y])
{
int x = p[i].x;
if(fa[x][12]<=n || !vis[x]){ans[p[i].id]=-1; continue;} p[i].k--;
for(int k=12;k>=0;k--) if(p[i].k >= (1<<k)){p[i].k-=(1<<k),x=fa[x][k]; if(x>n) break;}
if(x>n || x==0){ans[p[i].id]=-1; continue;}
else ans[p[i].id] = x;
}
}
for(int i=1;i<=q;i++) printf("%d\n",ans[i]);
return 0;
}