\(\text{Solution:}\)
一定要看好數據範圍!!!
從這題裏面學到了太多……
-
注意到連邊一定是小點往大點連的,所以一定沒有環。
-
詢問總量是固定的,總輸入量是 \(2\times 10^5\) 級別。
看到這裏起碼可以正常想題了……
首先,如果我們去暴力,那不難想到一個直接從點 \(x\) 往外暴力擴展的做法。這個做法的時間複雜度是 \(O(n).\)
那麼,有沒有其他想法?是不是可以預處理一下答案?我們發現如果要預處理的話,至少需要 \(O(n^2)\) 的複雜度。
注意如何預處理:我們需要從小到大枚舉點,按照從前到後的順序,把前面更新過的點維護的點集歸併到這個點上,這樣複雜度纔是最低的。
那麼兩個做法都過不了,考慮中和一下。
我們可以用預處理的方式處理每個點距離最遠的 \(O(\sqrt{n})\) 個點,然後對於詢問大於 \(\sqrt{n}\) 的詢問,我們發現,輸入總量是固定的! 也就是說,這種詢問不會超過 \(\sqrt{n}\) 次。
所以綜上,我們就可以做到一個 \(O(n\sqrt{n})\) 的解法了。
#include<bits/stdc++.h>
using namespace std;
const int N=4e5+10;
int n,m,Q,in[N],B,qr[N];
typedef pair<int,int> pr;
vector<pr>bk[N];
vector<int>G[N];
inline void link(int x,int y){G[x].push_back(y);}
inline int Max(int x,int y){return x>y?x:y;}
char buf[1<<21],*p1=buf,*p2=buf;
char obuf[1<<21],*O=obuf;
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++)
inline int read(){
int s=0,w=1;
char ch=getchar();
while(!isdigit(ch)){
if(ch=='-')w=-1;
ch=getchar();
}
while(isdigit(ch)){
s=s*10-'0'+ch;
ch=getchar();
}
return s*w;
}
inline void write(int x){
if(x<0){
x=-x;
*O++='-';
}
if(x>9)write(x/10);
*O++=x%10+'0';
}
#define mk make_pair
#define fi first
#define se second
vector<pr>pv,pu;
int vis[N];
void Do(){
for(int i=1;i<=n;++i){
bk[i].push_back(mk(0,i));
for(int j=0;j<(int)G[i].size();++j){
int v=G[i][j];
pv.clear();
for(int k=0;k<(int)bk[v].size();++k)pv.push_back(mk(bk[v][k].fi+1,bk[v][k].se));
pu.resize(bk[i].size()+bk[v].size());
merge(bk[i].begin(),bk[i].end(),pv.begin(),pv.end(),pu.begin(),greater<pr>());
bk[i].clear();
for(int k=0;k<pu.size()&&bk[i].size()<B;++k)
if(!vis[pu[k].se])vis[pu[k].se]=1,bk[i].push_back(pu[k]);
for(int k=0;k<(int)bk[i].size();++k)vis[bk[i][k].se]=0;
}
}
}
int f[N];
int solve(int x){
for(int i=1;i<=n;++i)f[i]=-(1<<30);
f[x]=0;
int ans=-1;
for(int i=x;i>=1;--i){
if(!vis[i])ans=Max(ans,f[i]);
for(int j=0;j<(int)G[i].size();++j)f[G[i][j]]=Max(f[G[i][j]],f[i]+1);
}
return ans;
}
int main(){
n=read();m=read();Q=read();
for(int i=1;i<=m;++i){
int u=read(),v=read();
link(v,u);
}
B=320;Do();
while(Q--){
int root=read(),num=read();
for(int i=1;i<=num;++i){qr[i]=read();vis[qr[i]]=1;}
if(num<B){
int res=-1;
for(int i=0;i<(int)bk[root].size();++i){
if(!vis[bk[root][i].se]){res=bk[root][i].fi;break;}
}
write(res);*O++='\n';
}
else {
write(solve(root));
*O++='\n';
}
for(int i=1;i<=num;++i)vis[qr[i]]=0;
}
fwrite(obuf,O-obuf,1,stdout);
return 0;
}