loj#2838 「JOISC 2018 Day 3」比太郎的聚会
分析
预处理每个点的前根号小的距离
对于每次询问删除点小于根号则已经处理好
否则直接暴力dp即可
代码
#include<bits/stdc++.h>
using namespace std;
#define fi first
#define se second
#define mp make_pair
const int b= 150;
int n,m,Q,dp[100010],vis[100010];
priority_queue<pair<int,int> >q[100010];
pair<int,int>d[100010][b+3];
vector<int>v[100010];
int main(){
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);
v[x].push_back(y);
}
for(i=1;i<=n;i++){
for(j=1;j<=b;j++)d[i][j]=mp(-1,0);
q[i].push(mp(0,i));
for(j=1;j<=b;j++){
while(!q[i].empty()&&vis[q[i].top().se]==i)q[i].pop();
if(q[i].empty())break;
d[i][j]=q[i].top();vis[q[i].top().se]=i;q[i].pop();
}
for(j=0;j<v[i].size();j++)
for(k=1;k<=b&&d[i][k].se;k++)
q[v[i][j]].push(mp(d[i][k].fi+1,d[i][k].se));
}
memset(vis,0,sizeof(vis));
for(int _=1;_<=Q;_++){
int x,y,z;
scanf("%d%d",&x,&y);
for(i=1;i<=y;i++)scanf("%d",&z),vis[z]=_;
if(y<b){
for(i=1;i<=b;i++)
if(vis[d[x][i].se]!=_){
printf("%d\n",d[x][i].fi);
break;
}
}else {
memset(dp,-1,sizeof(dp));
for(i=1;i<=n;i++){
if(vis[i]!=_)dp[i]=max(dp[i],0);
if(dp[i]>=0)for(j=0;j<v[i].size();j++)
dp[v[i][j]]=max(dp[v[i][j]],dp[i]+1);
}
printf("%d\n",dp[x]);
}
}
return 0;
}