这道题的数据范围中有两个需要注意到的点:
1. 边都是由编号小的点连向编号大的点.
2. 总点数只有 $10^5$ 个.
所以我们可以考虑采取根号分治的做法:
对于点数大于 $sqrt n$ 的部分,直接跑一个 $O(n)$ 的 DP.
对于点数小于 $sqrt n$ 的部分,提前预处理.
这样,时间复杂度就是 $O(n sqrt n)$ 的.
code:
#include <bits/stdc++.h> #define B 150 #define N 100060 #define setIO(s) freopen(s".in","r",stdin) using namespace std; int n,m,Q; int vis[N],dp[N]; priority_queue<pair<int,int> >q[N]; pair<int,int>d[N][B+3]; vector<int>G[N]; int main() { // setIO("input"); int i,j,k; scanf("%d%d%d",&n,&m,&Q); for(i=1;i<=m;++i) { int x,y; scanf("%d%d",&x,&y); G[x].push_back(y); } for(i=1;i<=n;++i) { for(j=1;j<=B;++j) d[i][j]=make_pair(-1,0); q[i].push(make_pair(0,i)); for(j=1;j<=B;++j) { while(!q[i].empty()&&vis[q[i].top().second]==i) q[i].pop(); if(q[i].empty()) break; d[i][j]=q[i].top(); vis[q[i].top().second]=i; q[i].pop(); } for(j=0;j<G[i].size();++j) for(k=1;k<=B&&d[i][k].second;++k) q[G[i][j]].push(make_pair(d[i][k].first+1,d[i][k].second)); } memset(vis,0,sizeof(vis)); for(i=1;i<=Q;++i) { int x,y,z; scanf("%d%d",&x,&y); for(j=1;j<=y;++j) scanf("%d",&z),vis[z]=i; if(y<B) { for(j=1;j<=B;++j) if(vis[d[x][j].second]!=i) { printf("%d ",d[x][j].first); break; } } else { memset(dp,-1,sizeof(dp)); for(j=1;j<=n;++j) { if(vis[j]!=i) dp[j]=max(dp[j],0); if(dp[j]>=0) { for(k=0;k<G[j].size();++k) dp[G[j][k]]=max(dp[G[j][k]],dp[j]+1); } } printf("%d ",dp[x]); } } return 0; }