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;
}

 

posted @ 2019-09-30 11:08  水题收割者  阅读(153)  评论(0编辑  收藏  举报